fix: resolve AccessError in POS session message posting by using sudo for partner access and message notification

This commit is contained in:
Suherdy Yacob 2026-05-29 11:34:46 +07:00
parent c70ce3d70e
commit 07125cdc43

View File

@ -1,22 +1,84 @@
from odoo import models from odoo import models, _
from odoo.tools import plaintext2html
class PosSession(models.Model): class PosSession(models.Model):
_inherit = 'pos.session' _inherit = 'pos.session'
def _get_message_author(self): def _get_message_author(self):
"""Override to read employee partner with sudo() to avoid res.partner """Read employee partner with sudo() to avoid res.partner access errors
access errors when the cashier's allowed companies don't include the for cashier users whose allowed companies don't include the partner's company_id.
company_id set on work_contact_id (caused by hr_multi_company_employee
assigning employees to branch companies).
""" """
if not self.employee_id: if not self.employee_id:
return None return None
# Use sudo() to bypass multi-company partner rule when reading
# the employee's work_contact_id or user partner for message posting.
employee = self.employee_id.sudo() employee = self.employee_id.sudo()
if related_partners := employee._get_related_partners(): related_partners = employee._get_related_partners()
if related_partners:
return related_partners[0] return related_partners[0]
return self.sudo().user_id.partner_id return self.sudo().user_id.partner_id
def _set_opening_control_data(self, cashbox_value: int, notes: str):
"""Override pos_hr's _set_opening_control_data to use sudo for message_post.
pos_hr does:
super()._set_opening_control_data(...)
if author_id := self._get_message_author():
self.message_post(body=..., author_id=author_id.id)
The problem: message_post internally reads the author res.partner in the
cashier's restricted context, causing an AccessError.
Fix: we call the SAME logic but with self.sudo().message_post().
"""
# Step 1: call the pos_hr super chain but stop before message_post.
# We do this by walking MRO to find the base pos.session method
# (skipping pos_hr's override) and calling it directly.
base_method = None
found_pos_hr = False
for cls in type(self).__mro__:
if found_pos_hr:
if '_set_opening_control_data' in cls.__dict__:
base_method = cls._set_opening_control_data
break
elif (cls.__name__ == 'PosSession'
and getattr(cls, '__module__', '').endswith('pos_hr.models.pos_session')):
found_pos_hr = True
if base_method:
base_method(self, cashbox_value, notes)
else:
# pos_hr not in MRO or already at base — call normal super
super()._set_opening_control_data(cashbox_value, notes)
# Step 2: re-implement pos_hr's message posting with sudo
author = self._get_message_author()
if author:
self.sudo().message_post(
body=plaintext2html(_('Opened register')),
author_id=author.id,
)
def post_close_register_message(self):
"""Override pos_hr's post_close_register_message to use sudo for message_post."""
author = self._get_message_author()
if author:
self.sudo().message_post(
body=plaintext2html(_('Closed Register')),
author_id=author.id,
)
else:
# No employee — call the base pos.session fallback
base_method = None
found_pos_hr = False
for cls in type(self).__mro__:
if found_pos_hr:
if 'post_close_register_message' in cls.__dict__:
base_method = cls.post_close_register_message
break
elif (cls.__name__ == 'PosSession'
and getattr(cls, '__module__', '').endswith('pos_hr.models.pos_session')):
found_pos_hr = True
if base_method:
base_method(self)
else:
super().post_close_register_message()