From 471907521ae26735dd8ba44a4c3f5aa6fec60102 Mon Sep 17 00:00:00 2001
From: Enric Tobella
Date: Mon, 29 Sep 2025 19:02:43 +0200
Subject: [PATCH 1/3] [ADD] project_share
---
project_share/README.rst | 80 ++++
project_share/__init__.py | 3 +
project_share/__manifest__.py | 22 +
project_share/controllers/__init__.py | 1 +
project_share/controllers/portal.py | 14 +
project_share/hooks.py | 19 +
project_share/models/__init__.py | 3 +
project_share/models/project_collaborator.py | 10 +
project_share/models/project_project.py | 26 ++
project_share/models/project_task.py | 51 +++
project_share/pyproject.toml | 3 +
project_share/readme/CONTRIBUTORS.md | 2 +
project_share/readme/DESCRIPTION.md | 1 +
project_share/static/description/icon.png | Bin 0 -> 9455 bytes
project_share/static/description/index.html | 428 +++++++++++++++++++
project_share/views/project_collaborator.xml | 36 ++
16 files changed, 699 insertions(+)
create mode 100644 project_share/README.rst
create mode 100644 project_share/__init__.py
create mode 100644 project_share/__manifest__.py
create mode 100644 project_share/controllers/__init__.py
create mode 100644 project_share/controllers/portal.py
create mode 100644 project_share/hooks.py
create mode 100644 project_share/models/__init__.py
create mode 100644 project_share/models/project_collaborator.py
create mode 100644 project_share/models/project_project.py
create mode 100644 project_share/models/project_task.py
create mode 100644 project_share/pyproject.toml
create mode 100644 project_share/readme/CONTRIBUTORS.md
create mode 100644 project_share/readme/DESCRIPTION.md
create mode 100644 project_share/static/description/icon.png
create mode 100644 project_share/static/description/index.html
create mode 100644 project_share/views/project_collaborator.xml
diff --git a/project_share/README.rst b/project_share/README.rst
new file mode 100644
index 0000000000..cd6a34f334
--- /dev/null
+++ b/project_share/README.rst
@@ -0,0 +1,80 @@
+=============
+Project Share
+=============
+
+..
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! source digest: sha256:728663946988f1ca9235b8189903e7c22071abd089f85f75a3c954c3774e2b1b
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
+ :target: https://odoo-community.org/page/development-status
+ :alt: Beta
+.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github
+ :target: https://github.com/OCA/project/tree/17.0/project_share
+ :alt: OCA/project
+.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
+ :target: https://translation.odoo-community.org/projects/project-17-0/project-17-0-project_share
+ :alt: Translate me on Weblate
+.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/project&target_branch=17.0
+ :alt: Try me on Runboat
+
+|badge1| |badge2| |badge3| |badge4| |badge5|
+
+This module adds a new functionality on collaborators, so we can have
+readonly collaborators that are able to see kanban and list views in the
+same way we have in internal view.
+
+**Table of contents**
+
+.. contents::
+ :local:
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues `_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us to smash it by providing a detailed and welcomed
+`feedback `_.
+
+Do not contact contributors directly about support or help with technical issues.
+
+Credits
+=======
+
+Authors
+-------
+
+* Dixmit
+
+Contributors
+------------
+
+- `Dixmit `__
+
+ - Enric Tobella
+
+Maintainers
+-----------
+
+This module is maintained by the OCA.
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+This module is part of the `OCA/project `_ project on GitHub.
+
+You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/project_share/__init__.py b/project_share/__init__.py
new file mode 100644
index 0000000000..6487efb0df
--- /dev/null
+++ b/project_share/__init__.py
@@ -0,0 +1,3 @@
+from . import controllers
+from . import models
+from .hooks import post_init_hook
diff --git a/project_share/__manifest__.py b/project_share/__manifest__.py
new file mode 100644
index 0000000000..bcf95cd780
--- /dev/null
+++ b/project_share/__manifest__.py
@@ -0,0 +1,22 @@
+# Copyright 2025 Dixmit
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+{
+ "name": "Project Share",
+ "summary": """
+ Improve the Share view of projects,
+ showing the kanban view on readonly too
+ """,
+ "version": "17.0.1.0.0",
+ "license": "AGPL-3",
+ "author": "Dixmit,Odoo Community Association (OCA)",
+ "website": "https://github.com/OCA/project",
+ "depends": [
+ "project",
+ ],
+ "data": [
+ "views/project_collaborator.xml",
+ ],
+ "demo": [],
+ "post_init_hook": "post_init_hook",
+}
diff --git a/project_share/controllers/__init__.py b/project_share/controllers/__init__.py
new file mode 100644
index 0000000000..8c3feb6f56
--- /dev/null
+++ b/project_share/controllers/__init__.py
@@ -0,0 +1 @@
+from . import portal
diff --git a/project_share/controllers/portal.py b/project_share/controllers/portal.py
new file mode 100644
index 0000000000..f3dce150df
--- /dev/null
+++ b/project_share/controllers/portal.py
@@ -0,0 +1,14 @@
+# Copyright 2025 Dixmit
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+
+from odoo.addons.project.controllers.portal import ProjectCustomerPortal
+
+
+class ProjectSharePortal(ProjectCustomerPortal):
+ def _prepare_project_sharing_session_info(self, project, task=None):
+ res = super()._prepare_project_sharing_session_info(project, task=task)
+ res["user_context"]["draggable"] = bool(
+ project._check_project_sharing_access(check_readonly=True)
+ )
+ return res
diff --git a/project_share/hooks.py b/project_share/hooks.py
new file mode 100644
index 0000000000..4934a0cc8e
--- /dev/null
+++ b/project_share/hooks.py
@@ -0,0 +1,19 @@
+def post_init_hook(env):
+ env.ref("project.project_task_rule_portal_project_sharing").write(
+ {
+ "domain_force": """
+ [
+ ('project_id.privacy_visibility', '=', 'portal'),
+ ('active', '=', True),
+ '|',
+ ('project_id.message_partner_ids',
+ 'child_of',
+ [user.partner_id.commercial_partner_id.id]),
+ ('message_partner_ids',
+ 'child_of',
+ [user.partner_id.commercial_partner_id.id]),
+ ('project_id.edit_collaborator_ids.partner_id', 'in', [user.partner_id.id]),
+ ]
+ """
+ }
+ )
diff --git a/project_share/models/__init__.py b/project_share/models/__init__.py
new file mode 100644
index 0000000000..6b1f9e7fd6
--- /dev/null
+++ b/project_share/models/__init__.py
@@ -0,0 +1,3 @@
+from . import project_project
+from . import project_collaborator
+from . import project_task
diff --git a/project_share/models/project_collaborator.py b/project_share/models/project_collaborator.py
new file mode 100644
index 0000000000..111e662e91
--- /dev/null
+++ b/project_share/models/project_collaborator.py
@@ -0,0 +1,10 @@
+# Copyright 2025 Dixmit
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class ProjectCollaborator(models.Model):
+ _inherit = "project.collaborator"
+
+ readonly = fields.Boolean(default=False)
diff --git a/project_share/models/project_project.py b/project_share/models/project_project.py
new file mode 100644
index 0000000000..547ca6aadb
--- /dev/null
+++ b/project_share/models/project_project.py
@@ -0,0 +1,26 @@
+# Copyright 2025 Dixmit
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class ProjectProject(models.Model):
+ _inherit = "project.project"
+
+ edit_collaborator_ids = fields.One2many(
+ "project.collaborator",
+ "project_id",
+ string="Collaborators",
+ copy=False,
+ domain=[("readonly", "=", False)],
+ )
+
+ def _check_project_sharing_access(self, check_readonly=False):
+ result = super()._check_project_sharing_access()
+ if (
+ check_readonly
+ and isinstance(result, models.BaseModel)
+ and result._name == "project.collaborator"
+ ):
+ return result.filtered(lambda c: not c.readonly)
+ return result
diff --git a/project_share/models/project_task.py b/project_share/models/project_task.py
new file mode 100644
index 0000000000..19423747e9
--- /dev/null
+++ b/project_share/models/project_task.py
@@ -0,0 +1,51 @@
+# Copyright 2025 Dixmit
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from lxml import etree
+
+from odoo import api, models
+
+
+class ProjectTask(models.Model):
+ _inherit = "project.task"
+
+ @api.model
+ def get_view(self, view_id=None, view_type="form", **options):
+ result = super().get_view(view_id=view_id, view_type=view_type, **options)
+ if (
+ view_type == "kanban"
+ and view_id
+ == self.env.ref("project.project_sharing_project_task_view_kanban").id
+ and not self.env.context.get("draggable")
+ ):
+ doc = etree.XML(result["arch"])
+ nodes = doc.xpath("//kanban")
+ if nodes:
+ nodes[0].set("records_draggable", "0")
+ nodes[0].set("create", "0")
+ result["arch"] = etree.tostring(doc, encoding="unicode")
+ if (
+ view_type == "form"
+ and view_id
+ == self.env.ref("project.project_sharing_project_task_view_form").id
+ and not self.env.context.get("draggable")
+ ):
+ doc = etree.XML(result["arch"])
+ nodes = doc.xpath("//form")
+ if nodes:
+ nodes[0].set("edit", "0")
+ nodes[0].set("create", "0")
+ result["arch"] = etree.tostring(doc, encoding="unicode")
+ if (
+ view_type == "tree"
+ and view_id
+ == self.env.ref("project.project_sharing_project_task_view_tree").id
+ and not self.env.context.get("draggable")
+ ):
+ doc = etree.XML(result["arch"])
+ nodes = doc.xpath("//tree")
+ if nodes:
+ nodes[0].set("edit", "0")
+ nodes[0].set("create", "0")
+ result["arch"] = etree.tostring(doc, encoding="unicode")
+ return result
diff --git a/project_share/pyproject.toml b/project_share/pyproject.toml
new file mode 100644
index 0000000000..4231d0cccb
--- /dev/null
+++ b/project_share/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["whool"]
+build-backend = "whool.buildapi"
diff --git a/project_share/readme/CONTRIBUTORS.md b/project_share/readme/CONTRIBUTORS.md
new file mode 100644
index 0000000000..164b6bea97
--- /dev/null
+++ b/project_share/readme/CONTRIBUTORS.md
@@ -0,0 +1,2 @@
+- [Dixmit](https://www.dixmit.com)
+ - Enric Tobella
\ No newline at end of file
diff --git a/project_share/readme/DESCRIPTION.md b/project_share/readme/DESCRIPTION.md
new file mode 100644
index 0000000000..9ea95d1e7f
--- /dev/null
+++ b/project_share/readme/DESCRIPTION.md
@@ -0,0 +1 @@
+This module adds a new functionality on collaborators, so we can have readonly collaborators that are able to see kanban and list views in the same way we have in internal view.
diff --git a/project_share/static/description/icon.png b/project_share/static/description/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d
GIT binary patch
literal 9455
zcmW++2RxMjAAjx~&dlBk9S+%}OXg)AGE&Cb*&}d0jUxM@u(PQx^-s)697TX`ehR4?GS^qbkof1cslKgkU)h65qZ9Oc=ml_0temigYLJfnz{IDzUf>bGs4N!v3=Z3jMq&A#7%rM5eQ#dc?k~!
zVpnB`o+K7|Al`Q_U;eD$B
zfJtP*jH`siUq~{KE)`jP2|#TUEFGRryE2`i0**z#*^6~AI|YzIWy$Cu#CSLW3q=GA
z6`?GZymC;dCPk~rBS%eCb`5OLr;RUZ;D`}um=H)BfVIq%7VhiMr)_#G0N#zrNH|__
zc+blN2UAB0=617@>_u;MPHN;P;N#YoE=)R#i$k_`UAA>WWCcEVMh~L_
zj--gtp&|K1#58Yz*AHCTMziU1Jzt_jG0I@qAOHsk$2}yTmVkBp_eHuY$A9)>P6o~I
z%aQ?!(GqeQ-Y+b0I(m9pwgi(IIZZzsbMv+9w{PFtd_<_(LA~0H(xz{=FhLB@(1&qHA5EJw1>>=%q2f&^X>IQ{!GJ4e9U
z&KlB)z(84HmNgm2hg2C0>WM{E(DdPr+EeU_N@57;PC2&DmGFW_9kP&%?X4}+xWi)(
z;)z%wI5>D4a*5XwD)P--sPkoY(a~WBw;E~AW`Yue4kFa^LM3X`8x|}ZUeMnqr}>kH
zG%WWW>3ml$Yez?i%)2pbKPI7?5o?hydokgQyZsNEr{a|mLdt;X2TX(#B1j35xPnPW
z*bMSSOauW>o;*=kO8ojw91VX!qoOQb)zHJ!odWB}d+*K?#sY_jqPdg{Sm2HdYzdEx
zOGVPhVRTGPtv0o}RfVP;Nd(|CB)I;*t&QO8h
zFfekr30S!-LHmV_Su-W+rEwYXJ^;6&3|L$mMC8*bQptyOo9;>Qb9Q9`ySe3%V$A*9
zeKEe+b0{#KWGp$F+tga)0RtI)nhMa-K@JS}2krK~n8vJ=Ngm?R!9G<~RyuU0d?nz#
z-5EK$o(!F?hmX*2Yt6+coY`6jGbb7tF#6nHA
zuKk=GGJ;ZwON1iAfG$E#Y7MnZVmrY|j0eVI(DN_MNFJmyZ|;w4tf@=CCDZ#5N_0K=
z$;R~bbk?}TpfDjfB&aiQ$VA}s?P}xPERJG{kxk5~R`iRS(SK5d+Xs9swCozZISbnS
zk!)I0>t=A<-^z(cmSFz3=jZ23u13X><0b)P)^1T_))Kr`e!-pb#q&J*Q`p+B6la%C
zuVl&0duN<;uOsB3%T9Fp8t{ED108)`y_~Hnd9AUX7h-H?jVuU|}My+C=TjH(jKz
zqMVr0re3S$H@t{zI95qa)+Crz*5Zj}Ao%4Z><+W(nOZd?gDnfNBC3>M8WE61$So|P
zVvqH0SNtDTcsUdzaMDpT=Ty0pDHHNL@Z0w$Y`XO
z2M-_r1S+GaH%pz#Uy0*w$Vdl=X=rQXEzO}d6J^R6zjM1u&c9vYLvLp?W7w(?np9x1
zE_0JSAJCPB%i7p*Wvg)pn5T`8k3-uR?*NT|J`eS#_#54p>!p(mLDvmc-3o0mX*mp_
zN*AeS<>#^-{S%W<*mz^!X$w_2dHWpcJ6^j64qFBft-o}o_Vx80o0>}Du;>kLts;$8
zC`7q$QI(dKYG`Wa8#wl@V4jVWBRGQ@1dr-hstpQL)Tl+aqVpGpbSfN>5i&QMXfiZ>
zaA?T1VGe?rpQ@;+pkrVdd{klI&jVS@I5_iz!=UMpTsa~mBga?1r}aRBm1WS;TT*s0f0lY=JBl66Upy)-k4J}lh=P^8(SXk~0xW=T9v*B|gzIhN
z>qsO7dFd~mgxAy4V?&)=5ieYq?zi?ZEoj)&2o)RLy=@hbCRcfT5jigwtQGE{L*8<@Yd{zg;CsL5mvzfDY}P-wos_6PfprFVaeqNE%h
zKZhLtcQld;ZD+>=nqN~>GvROfueSzJD&BE*}XfU|H&(FssBqY=hPCt`d
zH?@s2>I(|;fcW&YM6#V#!kUIP8$Nkdh0A(bEVj``-AAyYgwY~jB
zT|I7Bf@%;7aL7Wf4dZ%VqF$eiaC38OV6oy3Z#TER2G+fOCd9Iaoy6aLYbPTN{XRPz
z;U!V|vBf%H!}52L2gH_+j;`bTcQRXB+y9onc^wLm5wi3-Be}U>k_u>2Eg$=k!(l@I
zcCg+flakT2Nej3i0yn+g+}%NYb?ta;R?(g5SnwsQ49U8Wng8d|{B+lyRcEDvR3+`O{zfmrmvFrL6acVP%yG98X
zo&+VBg@px@i)%o?dG(`T;n*$S5*rnyiR#=wW}}GsAcfyQpE|>a{=$Hjg=-*_K;UtD
z#z-)AXwSRY?OPefw^iI+
z)AXz#PfEjlwTes|_{sB?4(O@fg0AJ^g8gP}ex9Ucf*@_^J(s_5jJV}c)s$`Myn|Kd
z$6>}#q^n{4vN@+Os$m7KV+`}c%4)4pv@06af4-x5#wj!KKb%caK{A&Y#Rfs
z-po?Dcb1({W=6FKIUirH&(yg=*6aLCekcKwyfK^JN5{wcA3nhO(o}SK#!CINhI`-I
z1)6&n7O&ZmyFMuNwvEic#IiOAwNkR=u5it{B9n2sAJV5pNhar=j5`*N!Na;c7g!l$
z3aYBqUkqqTJ=Re-;)s!EOeij=7SQZ3Hq}ZRds%IM*PtM$wV
z@;rlc*NRK7i3y5BETSKuumEN`Xu_8GP1Ri=OKQ$@I^ko8>H6)4rjiG5{VBM>B|%`&&s^)jS|-_95&yc=GqjNo{zFkw%%HHhS~e=s
zD#sfS+-?*t|J!+ozP6KvtOl!R)@@-z24}`9{QaVLD^9VCSR2b`b!KC#o;Ki<+wXB6
zx3&O0LOWcg4&rv4QG0)4yb}7BFSEg~=IR5#ZRj8kg}dS7_V&^%#Do==#`u
zpy6{ox?jWuR(;pg+f@mT>#HGWHAJRRDDDv~@(IDw&R>9643kK#HN`!1vBJHnC+RM&yIh8{gG2q
zA%e*U3|N0XSRa~oX-3EAneep)@{h2vvd3Xvy$7og(sayr@95+e6~Xvi1tUqnIxoIH
zVWo*OwYElb#uyW{Imam6f2rGbjR!Y3`#gPqkv57dB6K^wRGxc9B(t|aYDGS=m$&S!NmCtrMMaUg(c
zc2qC=2Z`EEFMW-me5B)24AqF*bV5Dr-M5ig(l-WPS%CgaPzs6p_gnCIvTJ=Y<6!gT
zVt@AfYCzjjsMEGi=rDQHo0yc;HqoRNnNFeWZgcm?f;cp(6CNylj36DoL(?TS7eU#+
z7&mfr#y))+CJOXQKUMZ7QIdS9@#-}7y2K1{8)cCt0~-X0O!O?Qx#E4Og+;A2SjalQ
zs7r?qn0H044=sDN$SRG$arw~n=+T_DNdSrarmu)V6@|?1-ZB#hRn`uilTGPJ@fqEy
zGt(f0B+^JDP&f=r{#Y_wi#AVDf-y!RIXU^0jXsFpf>=Ji*TeqSY!H~AMbJdCGLhC)
zn7Rx+sXw6uYj;WRYrLd^5IZq@6JI1C^YkgnedZEYy<&4(z%Q$5yv#Boo{AH8n$a
zhb4Y3PWdr269&?V%uI$xMcUrMzl=;w<_nm*qr=c3Rl@i5wWB;e-`t7D&c-mcQl7x!
zZWB`UGcw=Y2=}~wzrfLx=uet<;m3~=8I~ZRuzvMQUQdr+yTV|ATf1Uuomr__nDf=X
zZ3WYJtHp_ri(}SQAPjv+Y+0=fH4krOP@S&=zZ-t1jW1o@}z;xk8
z(Nz1co&El^HK^NrhVHa-_;&88vTU>_J33=%{if;BEY*J#1n59=07jrGQ#IP>@u#3A
z;!q+E1Rj3ZJ+!4bq9F8PXJ@yMgZL;>&gYA0%_Kbi8?S=XGM~dnQZQ!yBSgcZhY96H
zrWnU;k)qy`rX&&xlDyA%(a1Hhi5CWkmg(`Gb%m(HKi-7Z!LKGRP_B8@`7&hdDy5n=
z`OIxqxiVfX@OX1p(mQu>0Ai*v_cTMiw4qRt3~NBvr9oBy0)r>w3p~V0SCm=An6@3n)>@z!|o-$HvDK
z|3D2ZMJkLE5loMKl6R^ez@Zz%S$&mbeoqH5`Bb){Ei21q&VP)hWS2tjShfFtGE+$z
zzCR$P#uktu+#!w)cX!lWN1XU%K-r=s{|j?)Akf@q#3b#{6cZCuJ~gCxuMXRmI$nGtnH+-h
z+GEi!*X=AP<|fG`1>MBdTb?28JYc=fGvAi2I<$B(rs$;eoJCyR6_bc~p!XR@O-+sD
z=eH`-ye})I5ic1eL~TDmtfJ|8`0VJ*Yr=hNCd)G1p2MMz4C3^Mj?7;!w|Ly%JqmuW
zlIEW^Ft%z?*|fpXda>Jr^1noFZEwFgVV%|*XhH@acv8rdGxeEX{M$(vG{Zw+x(ei@
zmfXb22}8-?Fi`vo-YVrTH*C?a8%M=Hv9MqVH7H^J$KsD?>!SFZ;ZsvnHr_gn=7acz
z#W?0eCdVhVMWN12VV^$>WlQ?f;P^{(&pYTops|btm6aj>_Uz+hqpGwB)vWp0Cf5y<
zft8-je~nn?W11plq}N)4A{l8I7$!ks_x$PXW-2XaRFswX_BnF{R#6YIwMhAgd5F9X
zGmwdadS6(a^fjHtXg8=l?Rc0Sm%hk6E9!5cLVloEy4eh(=FwgP`)~I^5~pBEWo+F6
zSf2ncyMurJN91#cJTy_u8Y}@%!bq1RkGC~-bV@SXRd4F{R-*V`bS+6;W5vZ(&+I<9$;-V|eNfLa5n-6%
z2(}&uGRF;p92eS*sE*oR$@pexaqr*meB)VhmIg@h{uzkk$9~qh#cHhw#>O%)b@+(|
z^IQgqzuj~Sk(J;swEM-3TrJAPCq9k^^^`q{IItKBRXYe}e0Tdr=Huf7da3$l4PdpwWDop%^}n;dD#K4s#DYA8SHZ
z&1!riV4W4R7R#C))JH1~axJ)RYnM$$lIR%6fIVA@zV{XVyx}C+a-Dt8Y9M)^KU0+H
zR4IUb2CJ{Hg>CuaXtD50jB(_Tcx=Z$^WYu2u5kubqmwp%drJ6
z?Fo40g!Qd<-l=TQxqHEOuPX0;^z7iX?Ke^a%XT<13TA^5`4Xcw6D@Ur&VT&CUe0d}
z1GjOVF1^L@>O)l@?bD~$wzgf(nxX1OGD8fEV?TdJcZc2KoUe|oP1#=$$7ee|xbY)A
zDZq+cuTpc(fFdj^=!;{k03C69lMQ(|>uhRfRu%+!k&YOi-3|1QKB
z
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
Xviia!U7SGha1wx#SCgwmn*{w2TRX*I
literal 0
HcmV?d00001
diff --git a/project_share/static/description/index.html b/project_share/static/description/index.html
new file mode 100644
index 0000000000..680151d93d
--- /dev/null
+++ b/project_share/static/description/index.html
@@ -0,0 +1,428 @@
+
+
+
+
+
+Project Share
+
+
+
+
+
Project Share
+
+
+

+
This module adds a new functionality on collaborators, so we can have
+readonly collaborators that are able to see kanban and list views in the
+same way we have in internal view.
+
Table of contents
+
+
+
+
Bugs are tracked on GitHub Issues.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us to smash it by providing a detailed and welcomed
+feedback.
+
Do not contact contributors directly about support or help with technical issues.
+
+
+
+
+
+
+
+
This module is maintained by the OCA.
+
+
+
+
OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
This module is part of the OCA/project project on GitHub.
+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+
+
+
+
+
diff --git a/project_share/views/project_collaborator.xml b/project_share/views/project_collaborator.xml
new file mode 100644
index 0000000000..8d6c6997ab
--- /dev/null
+++ b/project_share/views/project_collaborator.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+ project.collaborator
+
+
+
+
+
+
+
+
+
+
+
+ project.collaborator
+
+
+
+
+
+
+
+
+
From eab01c53dbd6645712083b03acf4e9eec6e4bf6d Mon Sep 17 00:00:00 2001
From: Luis Rodriguez
Date: Tue, 17 Mar 2026 09:34:31 +0100
Subject: [PATCH 2/3] [IMP] project_share: pre-commit auto fixes
---
project_share/README.rst | 10 +++++-----
project_share/static/description/index.html | 6 +++---
project_share/views/project_collaborator.xml | 2 --
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/project_share/README.rst b/project_share/README.rst
index cd6a34f334..5ec11b0976 100644
--- a/project_share/README.rst
+++ b/project_share/README.rst
@@ -17,13 +17,13 @@ Project Share
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github
- :target: https://github.com/OCA/project/tree/17.0/project_share
+ :target: https://github.com/OCA/project/tree/18.0/project_share
:alt: OCA/project
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/project-17-0/project-17-0-project_share
+ :target: https://translation.odoo-community.org/projects/project-18-0/project-18-0-project_share
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
- :target: https://runboat.odoo-community.org/builds?repo=OCA/project&target_branch=17.0
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/project&target_branch=18.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -43,7 +43,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues `_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -75,6 +75,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
-This module is part of the `OCA/project `_ project on GitHub.
+This module is part of the `OCA/project `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/project_share/static/description/index.html b/project_share/static/description/index.html
index 680151d93d..e20c93a4a1 100644
--- a/project_share/static/description/index.html
+++ b/project_share/static/description/index.html
@@ -369,7 +369,7 @@ Project Share
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:728663946988f1ca9235b8189903e7c22071abd089f85f75a3c954c3774e2b1b
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-

+

This module adds a new functionality on collaborators, so we can have
readonly collaborators that are able to see kanban and list views in the
same way we have in internal view.
@@ -390,7 +390,7 @@
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
-feedback.
+feedback.
Do not contact contributors directly about support or help with technical issues.
@@ -419,7 +419,7 @@
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
-
This module is part of the OCA/project project on GitHub.
+
This module is part of the OCA/project project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/project_share/views/project_collaborator.xml b/project_share/views/project_collaborator.xml
index 8d6c6997ab..e995eb6f84 100644
--- a/project_share/views/project_collaborator.xml
+++ b/project_share/views/project_collaborator.xml
@@ -2,7 +2,6 @@
-
project.collaborator
@@ -32,5 +31,4 @@
-
From 93d6eb33f77b82884363688d36b4ed40bff4b259 Mon Sep 17 00:00:00 2001
From: Luis Rodriguez
Date: Tue, 17 Mar 2026 13:47:50 +0100
Subject: [PATCH 3/3] [MIG] project_share: Migration to 18.0
---
project_share/__init__.py | 1 +
project_share/__manifest__.py | 2 +-
project_share/views/project_collaborator.xml | 30 ++------
project_share/wizard/__init__.py | 2 +
.../project_share_collaborator_wizard.py | 10 +++
project_share/wizard/project_share_wizard.py | 73 +++++++++++++++++++
6 files changed, 94 insertions(+), 24 deletions(-)
create mode 100644 project_share/wizard/__init__.py
create mode 100644 project_share/wizard/project_share_collaborator_wizard.py
create mode 100644 project_share/wizard/project_share_wizard.py
diff --git a/project_share/__init__.py b/project_share/__init__.py
index 6487efb0df..4b84d5b082 100644
--- a/project_share/__init__.py
+++ b/project_share/__init__.py
@@ -1,3 +1,4 @@
from . import controllers
from . import models
+from . import wizard
from .hooks import post_init_hook
diff --git a/project_share/__manifest__.py b/project_share/__manifest__.py
index bcf95cd780..e0772445f3 100644
--- a/project_share/__manifest__.py
+++ b/project_share/__manifest__.py
@@ -7,7 +7,7 @@
Improve the Share view of projects,
showing the kanban view on readonly too
""",
- "version": "17.0.1.0.0",
+ "version": "18.0.1.0.0",
"license": "AGPL-3",
"author": "Dixmit,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/project",
diff --git a/project_share/views/project_collaborator.xml b/project_share/views/project_collaborator.xml
index e995eb6f84..a642e39f5d 100644
--- a/project_share/views/project_collaborator.xml
+++ b/project_share/views/project_collaborator.xml
@@ -2,32 +2,16 @@
-
- project.collaborator
-
+
+ project.share.wizard
+
-
-
-
+
-
-
-
-
-
-
- project.collaborator
-
-
-
-
diff --git a/project_share/wizard/__init__.py b/project_share/wizard/__init__.py
new file mode 100644
index 0000000000..c532d0a17b
--- /dev/null
+++ b/project_share/wizard/__init__.py
@@ -0,0 +1,2 @@
+from . import project_share_collaborator_wizard
+from . import project_share_wizard
diff --git a/project_share/wizard/project_share_collaborator_wizard.py b/project_share/wizard/project_share_collaborator_wizard.py
new file mode 100644
index 0000000000..5951fd9507
--- /dev/null
+++ b/project_share/wizard/project_share_collaborator_wizard.py
@@ -0,0 +1,10 @@
+# Copyright 2025 Dixmit
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class ProjectSharingCollaboratorWizard(models.TransientModel):
+ _inherit = "project.share.collaborator.wizard"
+
+ readonly = fields.Boolean(default=False)
diff --git a/project_share/wizard/project_share_wizard.py b/project_share/wizard/project_share_wizard.py
new file mode 100644
index 0000000000..849620477a
--- /dev/null
+++ b/project_share/wizard/project_share_wizard.py
@@ -0,0 +1,73 @@
+from odoo import Command, api, models
+
+
+class ProjectShareWizard(models.TransientModel):
+ _inherit = "project.share.wizard"
+
+ @api.model
+ def default_get(self, fields):
+ result = super().default_get(fields)
+ if result.get("collaborator_ids"):
+ new_commands = []
+
+ for cmd in result["collaborator_ids"]:
+ # cmd is like (0, 0, values)
+ if cmd[0] == 0:
+ values = dict(cmd[2]) # copy to not modify the original values
+
+ partner_id = values.get("partner_id")
+
+ # Search the original collaborator
+ collaborator = self.env["project.collaborator"].search(
+ [
+ ("partner_id", "=", partner_id),
+ ("project_id", "=", result.get("res_id")),
+ ],
+ limit=1,
+ )
+
+ # If not found, it is a follower with partner_share and
+ # readonly doesn't affect him
+ values["readonly"] = (
+ collaborator.readonly if collaborator else False
+ )
+
+ new_commands.append((0, 0, values))
+ else:
+ new_commands.append(cmd)
+
+ result["collaborator_ids"] = new_commands
+
+ return result
+
+ @api.model_create_multi
+ def create(self, vals_list):
+ wizards = super().create(vals_list)
+
+ collaborator_ids_vals_list = []
+ for wizard in wizards:
+ project = wizard.resource_ref
+ project_collaborator_per_partner_id = {
+ c.partner_id.id: c for c in project.collaborator_ids
+ }
+ for collaborator in wizard.collaborator_ids:
+ partner_id = collaborator.partner_id.id
+ project_collaborator = project_collaborator_per_partner_id.get(
+ partner_id, self.env["project.collaborator"]
+ )
+ # readonly attribute only has sense if the access mode is not 'read',
+ # otherwise kanban view won't be shown on portal
+ readonly = collaborator.access_mode != "read" and collaborator.readonly
+ collaborator_ids_vals_list.append(
+ Command.update(
+ project_collaborator.id,
+ {"readonly": readonly},
+ )
+ )
+ project_vals = {}
+ if collaborator_ids_vals_list:
+ project_vals["collaborator_ids"] = collaborator_ids_vals_list
+ if project_vals:
+ project.write(project_vals)
+
+ return wizards