from odoo import models, _ from odoo.tools import plaintext2html class PosSession(models.Model): _inherit = 'pos.session' def _get_message_author(self): """Read employee partner with sudo() to avoid res.partner access errors for cashier users whose allowed companies don't include the partner's company_id. """ if not self.employee_id: return None employee = self.employee_id.sudo() related_partners = employee._get_related_partners() if related_partners: return related_partners[0] 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()