From c70ce3d70e4f8016c80c6004d6636785a74b062c Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Fri, 29 May 2026 11:22:28 +0700 Subject: [PATCH] feat: add multi-company access support for POS sessions and employees by overriding partner security rules and load methods --- models/__init__.py | 1 + models/__pycache__/__init__.cpython-312.pyc | Bin 292 -> 327 bytes .../__pycache__/hr_employee.cpython-312.pyc | Bin 5212 -> 7288 bytes models/hr_employee.py | 34 ++++++++++++++++++ models/pos_session.py | 22 ++++++++++++ security/hr_security.xml | 6 +++- 6 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 models/pos_session.py diff --git a/models/__init__.py b/models/__init__.py index ab87c94..26e4cbc 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1,3 +1,4 @@ from . import hr_employee from . import pos_config +from . import pos_session from . import res_users diff --git a/models/__pycache__/__init__.cpython-312.pyc b/models/__pycache__/__init__.cpython-312.pyc index e5fbc03f6a0ad96ddae3f9b6d743ff311ab7818c..459921e65cafb545fe3472fcc8508673df00f2eb 100644 GIT binary patch delta 133 zcmZ3&bexIzG%qg~0}yx$OJ=1`n(;NW}qQOEFgjvM6gYqQlQKYWHAD9u^^E6 Yz|6?Vc$Y!)E`tP+yvHD3#0eAy03pyF;s5{u delta 98 zcmX@kw1kQGG%qg~0}v$r6wmUW$ScXHF;QKUrIJOHbz*|5G-pw2aeQfUYEiMDCd(~` sB4(hiK4HvVoQl{r&StRaiF?zY7}YUpmEZrz>u|dFe5?>juww?x)iA% z%61$`QHlkq4HT#iZm_okL)NDZ?n45nP8L0ZdlNlc5hme4c&kO`;ROo zPOu)3KY#xB%SZlo=)0HNziew$5u8)8gY##)*V_}vFTvXeGLV5Sl;uys!g(Pp);yzzDtX z{h{k+FN**2N_+*)V59q5WQ!ZX$#zk7{@Fc#KQ(%;p+`2c6?6$_4@{zTVmmB+E8xNH zn&e`f@{G{O__^(H_9yoK>;?{}T2&*a2?p=IFt`-87} zWx@t3p?Tn*KC8l3Ls}L~cwU62dz0MvsZ$aS{E4t7?1{^gH`3mtt_aYjcum>Do}(TL zm1T&~0uc_qRSuOxXV8b?oM57y@V0_bIa~@G(n0Vqg+1W|RYGM2WYQV*b^)}JQlz1k z7ZFnoxvUx?kcCfzhdtiZuJXOyQe)mtHP!=$A~&?jK6QIjU8$=TPzy$+td>+TQhBtJ z(lqDQ7%lahB1Y@~(X};n?OgW(lTb;TgnlsG_AFU)*gIOzv5R`HsF?Ov=cDOPNcS<{X#S`Ap8q7j%0WBDutHsB5Q+WG@*dmEs(I6tG?qFQ}0! z<&wv~;L06mX_4rA4d}TXbzK5&IgB_qapBE`r&FMI=26fKb9Ap&9+=Ub!=MbEQKDNg zhKjLFW=yL{88yiCGSMtYH?)G|YJ4b~;pBDGCew7rVUO$7VUUY_P;=mRjQ8G{g6R@h zpP}UItG^&iGzCc<+ggUKmVSxbL$l4^2wSjdMjdSq^VKvCB%VCCAO9T5F}NQ9`p_@& z23p1Qh+`+-z&MB>9r$*nI0_9a~2BquJXFA&r$}vV9$e+rGW%( zx@Bp5Hn5{W1dShCs)xp z#xf@@C#PHPI52xI??3=|2*`I=(PpTc81)mQ)x?;e7`vVPVYW4)o;|c)nrXZkpndaJu_4#6F!-^OU~{n{kt!}{^$NTZXVw>t{?x^{Efr@KxU`^ zjUD9>(0hr)_fcEqHN0|ewvtU6jgvKLw~`)NQ#SkVbROA_9^5>K3vfWuv?e*DaZZfcr|(2hbwxzuDr)1-6Mxr&aF-Pt^K>n7jMqpF5a^J z5GXCHzpFZago&)($Gk041YQ4O=+5qb8+fjP|b3cg& z-o$PQ2KU*Kwuxg>T4emQI)6Uh?ftuROJI5LH_=Rp@8A8KcPIM!KutI(XL0Q%6pFlm z@x6=x6o}mSKt!RAhn(|%-Sx#u8?2eb3I9c~cRAq^7~>?x$+Mi)KO_G6vdc~KbMK?r zXa|2yM}ja1uw_nre~P8>W$*h~|3n2e{Ac980Hh{jjK4zde@CgiDD_Y(VcfUYv(dNS X_YiUZ;T2KAp|wT6^?xB?>lyzC&Uce| delta 371 zcmexiaYuviG%qg~0}!+dOJrT=o5&}jQvl>mXGmd4Va#F3WsG9XWr||TWsYLbWr<>8 zWME=&XGmdcVMt+4Wz6E57$wcm1{Pug3b8_jWH>9?G}&K*Or5yOfYpGJfuVi!1u5&v zQj9lc#X1<$7*j-BI9G$@fgnn#gQ0>kN;sH7Q+%@t(+eg>xy`by#f*$E<@>Pt1%in=AQa7#STWUlVZR)?_YX0-EFJrztY|jl}B7b0oFd zn1KStM<<_^JjC{eNs={+aq?QJqf)*=(IP((;SVALKm-ej2%Ov_Ex{EDVuFao$?K$z z*+DEnO^(SQq}3TCCril4I>iD-fSzF}HUJVIm>C%v?=z@hW>Eja62S-zs0m`zWhTme cVE}W!)G%={vP~$PUNf=gD+7>OBoEXC0DuHm8~^|S diff --git a/models/hr_employee.py b/models/hr_employee.py index 01d63c0..252478d 100644 --- a/models/hr_employee.py +++ b/models/hr_employee.py @@ -1,3 +1,4 @@ +import hashlib from odoo import models, fields, api, _ class HrEmployee(models.Model): @@ -91,7 +92,40 @@ class HrEmployee(models.Model): return super()._search(domain, offset=offset, limit=limit, order=order, **kwargs) + @api.model + def _load_pos_data_read(self, records, config): + """Override to read employee data (including work_contact_id / res.partner) + with sudo() so cashier users whose user.company_ids doesn't include the + employee partner's company_id don't get a read access error on session open. + The employee records are already filtered by _load_pos_data_domain before + arriving here, so sudo() is safe — we're only relaxing the partner rule. + """ + fields = self._load_pos_data_fields(config) + # Read with sudo to bypass res.partner multi-company rule for work_contact_id + read_records = records.sudo().read(fields, load=False) + manager_ids = records.filtered( + lambda emp: config.group_pos_manager_id.id in emp.user_id.all_group_ids.ids + ).ids + employees_barcode_pin = records.get_barcodes_and_pin_hashed() + bp_per_employee_id = {bp_e['id']: bp_e for bp_e in employees_barcode_pin} + + for employee in read_records: + if employee['id'] in manager_ids: + role = 'manager' + employee['_user_role'] = 'admin' + elif employee['id'] in config.advanced_employee_ids.ids: + role = 'manager' + elif employee['id'] in config.minimal_employee_ids.ids: + role = 'minimal' + else: + role = 'cashier' + + employee['_role'] = role + employee['_barcode'] = bp_per_employee_id[employee['id']]['barcode'] + employee['_pin'] = bp_per_employee_id[employee['id']]['pin'] + + return read_records class HrEmployeePublic(models.Model): diff --git a/models/pos_session.py b/models/pos_session.py new file mode 100644 index 0000000..24287c8 --- /dev/null +++ b/models/pos_session.py @@ -0,0 +1,22 @@ +from odoo import models + + +class PosSession(models.Model): + _inherit = 'pos.session' + + def _get_message_author(self): + """Override to read employee partner with sudo() to avoid res.partner + access errors when the cashier's allowed companies don't include the + company_id set on work_contact_id (caused by hr_multi_company_employee + assigning employees to branch companies). + """ + if not self.employee_id: + 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() + if related_partners := employee._get_related_partners(): + return related_partners[0] + + return self.sudo().user_id.partner_id diff --git a/security/hr_security.xml b/security/hr_security.xml index d2bf101..6b6e66f 100644 --- a/security/hr_security.xml +++ b/security/hr_security.xml @@ -16,7 +16,11 @@ - ['|', '|', ('partner_share', '=', False), ('company_id', 'parent_of', company_ids), ('company_id', '=', False)] + + ['|', '|', '|', ('partner_share', '=', False), ('company_id', 'parent_of', company_ids), ('company_id', 'in', user.company_ids.ids), ('company_id', '=', False)]