Browse Source

Merge PR #863 into 12.0

Signed-off-by NL66278
12.0
OCA-git-bot 4 years ago
parent
commit
be0aa4e209
  1. 167
      partner_multi_relation_tabs/README.rst
  2. 3
      partner_multi_relation_tabs/__init__.py
  3. 31
      partner_multi_relation_tabs/__manifest__.py
  4. 17
      partner_multi_relation_tabs/demo/res_partner_category_demo.xml
  5. 48
      partner_multi_relation_tabs/demo/res_partner_demo.xml
  6. 30
      partner_multi_relation_tabs/demo/res_partner_relation_demo.xml
  7. 41
      partner_multi_relation_tabs/demo/res_partner_relation_type_demo.xml
  8. 34
      partner_multi_relation_tabs/demo/res_partner_tab_demo.xml
  9. 266
      partner_multi_relation_tabs/i18n/da.po
  10. 276
      partner_multi_relation_tabs/i18n/nl.po
  11. 264
      partner_multi_relation_tabs/i18n/partner_multi_relation_tabs.pot
  12. 6
      partner_multi_relation_tabs/models/__init__.py
  13. 100
      partner_multi_relation_tabs/models/res_partner.py
  14. 56
      partner_multi_relation_tabs/models/res_partner_relation_all.py
  15. 59
      partner_multi_relation_tabs/models/res_partner_relation_type.py
  16. 35
      partner_multi_relation_tabs/models/res_partner_relation_type_selection.py
  17. 95
      partner_multi_relation_tabs/models/res_partner_tab.py
  18. 5
      partner_multi_relation_tabs/readme/CONTRIBUTORS.rst
  19. 9
      partner_multi_relation_tabs/readme/DESCRIPTION.rst
  20. 78
      partner_multi_relation_tabs/readme/USAGE.rst
  21. 3
      partner_multi_relation_tabs/security/ir.model.access.csv
  22. BIN
      partner_multi_relation_tabs/static/description/icon.png
  23. 497
      partner_multi_relation_tabs/static/description/index.html
  24. BIN
      partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-display.png
  25. BIN
      partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-edit.png
  26. BIN
      partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-search.png
  27. BIN
      partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-type-configuration.png
  28. BIN
      partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-tab-configuration.png
  29. 2
      partner_multi_relation_tabs/tablib/__init__.py
  30. 83
      partner_multi_relation_tabs/tablib/tab.py
  31. 4
      partner_multi_relation_tabs/tests/__init__.py
  32. 50
      partner_multi_relation_tabs/tests/common.py
  33. 157
      partner_multi_relation_tabs/tests/test_partner_tabs.py
  34. 39
      partner_multi_relation_tabs/tests/test_tab.py
  35. 18
      partner_multi_relation_tabs/views/menu.xml
  36. 17
      partner_multi_relation_tabs/views/res_partner_relation_all.xml
  37. 20
      partner_multi_relation_tabs/views/res_partner_relation_type.xml
  38. 44
      partner_multi_relation_tabs/views/res_partner_tab.xml
  39. 1
      setup/_metapackage/setup.py

167
partner_multi_relation_tabs/README.rst

@ -0,0 +1,167 @@
=================================
Show partner relations in own tab
=================================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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%2Fpartner--contact-lightgray.png?logo=github
:target: https://github.com/OCA/partner-contact/tree/12.0/partner_multi_relation_tabs
:alt: OCA/partner-contact
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/partner-contact-12-0/partner-contact-12-0-partner_multi_relation_tabs
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/134/12.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module adds the possibility to show certain partner relations in a
tab on the partner form, in addition to in the list of all relations.
This can be useful if certain relation types are regularly used and should
be overseeable at a glace.
For instance you can make a tab named 'board' that will show all the board
members of a company, by showing the relations of types ceo, cto, cfo and
board member.
**Table of contents**
.. contents::
:local:
Usage
=====
Relation Type Tabs
~~~~~~~~~~~~~~~~~~
Before being able to show certain types of relations on a tab in the partner
form, you will have to define the tab.
Do that in Contacts / Relations / Relation Tabs.
.. image:: https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-tab-configuration.png
If you specify nothing, the tab will be shown on all partner forms that have
tabs (page elements). Normally you will select to show the tab only on
partners that are companies/organisations, or only for persons. You can also
select a category to further limit for which partners the tab wil be shown.
The possibility exists to show a tab only on specific partners. For instance
on your own company partner.
Relation Types
~~~~~~~~~~~~~~
In configuring the relation types, you can select which type of relation will
be shown on which tab. It is possible to show multiple types on one tab.
Do that in Contacts / Relations / Relation Types.
For example on a 'executive board' tab, you might want to show the CEO of a
company, but also the CFO, the CTO and normal board members.
You might specify a tab for both the 'left side' of a relation, as for the
'right side' or inverse relation. So a relation 'company has ceo', with
inverse type 'person is ceo of' might specify the 'board' tab for the
company type of the relation, but possibly a 'positions held' tab for the
person side of the relation, so on the partner form of a person you see in
one tab all positions or functions a person has, regardless in which company
or organisation.
For each side of a relation, the partner contact type and the partner category
must be consistent with those specified for the tab.
.. image:: https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-type-configuration.png
Partner Form
~~~~~~~~~~~~
The partner form will contain extra tab pages, for each tab that is
appropiate for that partner. So a company partner does not show the tabs that
are meant for persons and vice versa. Also tabs meant for partners with
a certain category/label will only show if partners have that label.
When adding relations on a tab, only relation types appropiate for that tab
can be selected.
Example of adding a relation:
.. image:: https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-edit.png
Example of a filled out board tab:
.. image:: https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-display.png
Deleting tabs
~~~~~~~~~~~~~
When a tab is deleted, this will in no way effect the existing relations.
However the references on the relation types to the deleted tabs will also be
cleared.
Searching Relations by Tab
~~~~~~~~~~~~~~~~~~~~~~~~~~
You can search relations with the tab on which they are shown. For instance
to find all board members.
Do that in Contacts / Relations / Relations.
.. image:: https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-search.png
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/partner-contact/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/partner-contact/issues/new?body=module:%20partner_multi_relation_tabs%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Therp BV
Contributors
~~~~~~~~~~~~
* Holger Brunn <hbrunn@therp.nl>
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
* Stéphane Bidoul <stephane.bidoul@acsone.eu>
* Ronald Portier <ronald@therp.nl>
* George Daramouskas <gdaramouskas@therp.nl>
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/partner-contact <https://github.com/OCA/partner-contact/tree/12.0/partner_multi_relation_tabs>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

3
partner_multi_relation_tabs/__init__.py

@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import tablib
from . import models

31
partner_multi_relation_tabs/__manifest__.py

@ -0,0 +1,31 @@
# Copyright 2014-2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Show partner relations in own tab",
"version": "12.0.1.0.0",
"author": "Therp BV,Odoo Community Association (OCA)",
"license": "AGPL-3",
"complexity": "normal",
"category": "Customer Relationship Management",
"depends": [
'partner_multi_relation',
],
"demo": [
"demo/res_partner_category_demo.xml",
"demo/res_partner_tab_demo.xml",
"demo/res_partner_demo.xml",
"demo/res_partner_relation_type_demo.xml",
"demo/res_partner_relation_demo.xml",
],
"data": [
"views/res_partner_tab.xml",
"views/res_partner_relation_type.xml",
"views/res_partner_relation_all.xml",
'views/menu.xml',
'security/ir.model.access.csv',
],
"auto_install": False,
"installable": True,
"application": False,
}

17
partner_multi_relation_tabs/demo/res_partner_category_demo.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- Categories -->
<record id="category_government" model="res.partner.category">
<field name="name">Government</field>
</record>
<record id="category_functionary" model="res.partner.category">
<field name="name">Functionary</field>
</record>
<record id="category_department" model="res.partner.category">
<field name="name">Department</field>
</record>
</odoo>

48
partner_multi_relation_tabs/demo/res_partner_demo.xml

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- Partners -->
<record id="partner_big_company" model="res.partner">
<field name="name">Big company</field>
<field name="is_company">1</field>
<field name="customer" eval="1"/>
<field name="ref">BIG</field>
</record>
<record id="partner_important_person" model="res.partner">
<field
name="category_id"
eval="[(6,0,[ref('category_functionary')])]"
/>
<field name="name">Bart Simpson</field>
<field name="is_company">0</field>
<field name="ref">BS</field>
</record>
<record id="partner_common_person" model="res.partner">
<field name="name">Homer Simpson</field>
<field name="is_company">0</field>
<field name="ref">HS</field>
</record>
<record id="partner_programming_department" model="res.partner">
<field
name="category_id"
eval="[(6,0,[ref('category_department')])]"
/>
<field name="name">Programming</field>
<field name="is_company">1</field>
<field name="ref">HACKDEP</field>
</record>
<record id="partner_helpdesk_department" model="res.partner">
<field
name="category_id"
eval="[(6,0,[ref('category_department')])]"
/>
<field name="name">Helpdesk</field>
<field name="is_company">1</field>
<field name="ref">HELPDEP</field>
</record>
</odoo>

30
partner_multi_relation_tabs/demo/res_partner_relation_demo.xml

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- Company has ceo. -->
<record id="relation_company_ceo" model="res.partner.relation">
<field name="left_partner_id" ref="partner_big_company" />
<field name="right_partner_id" ref="partner_important_person" />
<field name="type_id" ref="relation_type_company_has_ceo" />
</record>
<!-- Departments of main organisation. -->
<record id="relation_programming_department" model="res.partner.relation">
<field name="left_partner_id" ref="base.main_partner" />
<field name="right_partner_id" ref="partner_programming_department" />
<field
name="type_id"
ref="relation_type_organisation_has_department"
/>
</record>
<record id="relation_helpdesk_department" model="res.partner.relation">
<field name="left_partner_id" ref="base.main_partner" />
<field name="right_partner_id" ref="partner_helpdesk_department" />
<field
name="type_id"
ref="relation_type_organisation_has_department"
/>
</record>
</odoo>

41
partner_multi_relation_tabs/demo/res_partner_relation_type_demo.xml

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- Company has CEO: organisation to functionary person -->
<record
id="relation_type_company_has_ceo"
model="res.partner.relation.type">
<field name="name">has ceo</field>
<field name="name_inverse">is ceo of</field>
<field name="contact_type_left">c</field>
<field name="tab_left_id" ref="tab_board" />
<field name="contact_type_right">p</field>
<field name="partner_category_right" ref="category_functionary"/>
</record>
<!-- Committee has a chairperson -->
<record
id="relation_type_committee_has_chairperson"
model="res.partner.relation.type">
<field name="name">has chairperson</field>
<field name="name_inverse">is chairperson of</field>
<field name="contact_type_left">c</field>
<field name="tab_left_id" ref="tab_committee" />
<field name="contact_type_right">p</field>
<field name="partner_category_left" ref="category_government"/>
<field name="partner_category_right" ref="category_functionary"/>
<field name="tab_right_id" ref="tab_positions" />
</record>
<!-- Organisation has department -->
<record
id="relation_type_organisation_has_department"
model="res.partner.relation.type">
<field name="name">has department</field>
<field name="name_inverse">is department of</field>
<field name="tab_left_id" ref="tab_departments" />
<field name="contact_type_right">c</field>
<field name="partner_category_right" ref="category_department"/>
</record>
</odoo>

34
partner_multi_relation_tabs/demo/res_partner_tab_demo.xml

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="tab_committee" model="res.partner.tab">
<field name="code">committee</field>
<field name="name">Government committee</field>
<field name="contact_type">c</field>
<field name="partner_category_id" ref="category_government" />
</record>
<record id="tab_board" model="res.partner.tab">
<field name="code">board</field>
<field name="name">Company executive board</field>
<field name="contact_type">c</field>
</record>
<record id="tab_positions" model="res.partner.tab">
<field name="code">positions</field>
<field name="name">Positions held</field>
<field name="contact_type">p</field>
<field name="partner_category_id" ref="category_functionary" />
</record>
<!-- Tab that will only be shown on our own main company partner. -->
<record id="tab_departments" model="res.partner.tab">
<field name="code">departments</field>
<field name="name">Our departments</field>
<field
name="partner_ids"
eval="[(6,0,[ref('base.main_partner')])]"
/>
</record>
</odoo>

266
partner_multi_relation_tabs/i18n/da.po

@ -0,0 +1,266 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_multi_relation_tabs
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2019-05-09 07:03+0000\n"
"Last-Translator: Hans Henrik Gabelgaard <hhg@gabelgaard.org>\n"
"Language-Team: none\n"
"Language: da\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.5.1\n"
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_all
msgid "All (non-inverse + inverse) relations between partners"
msgstr "Alle (non-inverse + inverse) relationer mellem partnere"
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_type_selection
msgid "All relation types"
msgstr "Alle relationstyper"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_code
msgid "Code"
msgstr "Kode"
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_board
msgid "Company executive board"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner
msgid "Contact"
msgstr "Kontakt"
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:33
#, python-format
msgid "Contact type left not compatible with left tab"
msgstr "Kontakt type venstre er ikke kompatibel med venstre fane"
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:53
#, python-format
msgid "Contact type right not compatible with right tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_create_uid
msgid "Created by"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_create_date
msgid "Created on"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_department
msgid "Department"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_display_name
msgid "Display Name"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_functionary
msgid "Functionary"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "General"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_government
msgid "Government"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_committee
msgid "Government committee"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_id
msgid "ID"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_code
msgid "Language independent code for tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab___last_update
msgid "Last Modified on"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_write_uid
msgid "Last Updated by"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_write_date
msgid "Last Updated on"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_name
msgid "Name"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_departments
msgid "Our departments"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/tablib/tab.py:56
#, python-format
msgid "Partner"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_type
msgid "Partner Relation Type"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:38
#, python-format
msgid "Partner category left not compatible with left tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:58
#, python-format
msgid "Partner category right not compatible with right tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_partner_ids
msgid "Partners with this tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_positions
msgid "Positions held"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.actions.act_window,name:partner_multi_relation_tabs.action_res_partner_tab
#: model:ir.ui.menu,name:partner_multi_relation_tabs.menu_res_partner_tab
msgid "Relation Tabs"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "Select partner type and category for tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "Select specific partners to have this tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_all_tab_id
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_selection_tab_id
msgid "Show relation on tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_tab_right_id
msgid "Tab for inverse relation"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_tab_left_id
msgid "Tab for this relation"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_relation_type_tab_right_id
msgid "Tab in which inverse relations will be visible on partner."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_relation_type_tab_left_id
msgid "Tab in which these relations will be visible on partner."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_tab
msgid "Tabs to add to partner"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_partner_ids
msgid "This tab will only show for certain partners.\n"
"Do not combine this with selection for contact type or category."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_partner_category_id
msgid "Valid for partner category"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_contact_type
msgid "Valid for partner type"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_name
msgid "Will provide title for tab in user language"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_tab.py:49
#, python-format
msgid "You can not both specify partner_ids and other criteria."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_company_has_ceo
msgid "has ceo"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_committee_has_chairperson
msgid "has chairperson"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_organisation_has_department
msgid "has department"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_company_has_ceo
msgid "is ceo of"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_committee_has_chairperson
msgid "is chairperson of"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_organisation_has_department
msgid "is department of"
msgstr ""

276
partner_multi_relation_tabs/i18n/nl.po

@ -0,0 +1,276 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_multi_relation_tabs
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-11-01 09:32+0000\n"
"PO-Revision-Date: 2017-11-01 09:32+0000\n"
"Last-Translator: Ronald Portier <ronald@therp.nl>, 2017\n"
"Language-Team: Dutch (https://www.transifex.com/oca/teams/23907/nl/)\n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_all
msgid "All (non-inverse + inverse) relations between partners"
msgstr "Alle connecties (van beide kanten) tussen relaties"
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_type_selection
msgid "All relation types"
msgstr "Alle connectie types"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_code
msgid "Code"
msgstr "Code"
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_board
msgid "Company executive board"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner
msgid "Contact"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:33
#, python-format
msgid "Contact type left not compatible with left tab"
msgstr "Linker type contact is niet verenigbaar met linker tab"
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:53
#, python-format
msgid "Contact type right not compatible with right tab"
msgstr "Rechter type contact is niet verenigbaar met rechter tab"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_create_uid
msgid "Created by"
msgstr "Aangemaakt door"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_create_date
msgid "Created on"
msgstr "Aangemaakt op"
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_department
msgid "Department"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_display_name
msgid "Display Name"
msgstr "Naam weergave"
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_functionary
msgid "Functionary"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "General"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_government
msgid "Government"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_committee
msgid "Government committee"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_id
msgid "ID"
msgstr "ID"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_code
msgid "Language independent code for tab"
msgstr "Taal onafhankelijke code voor tab"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab___last_update
msgid "Last Modified on"
msgstr "Laatst gewijzigd op"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_write_uid
msgid "Last Updated by"
msgstr "Laatst gewijzigd door"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_write_date
msgid "Last Updated on"
msgstr "Laatst gewijzigd op"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_name
msgid "Name"
msgstr "Naam"
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_departments
msgid "Our departments"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/tablib/tab.py:56
#, python-format
msgid "Partner"
msgstr "Relatie"
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_type
msgid "Partner Relation Type"
msgstr "Type connectie"
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:38
#, python-format
msgid "Partner category left not compatible with left tab"
msgstr "Categorie van linker partner is niet verenigbaar met linker tab"
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:58
#, python-format
msgid "Partner category right not compatible with right tab"
msgstr "Categorie van rechter partner is niet verenigbaar met rechter tab"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_partner_ids
msgid "Partners with this tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_positions
msgid "Positions held"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.actions.act_window,name:partner_multi_relation_tabs.action_res_partner_tab
#: model:ir.ui.menu,name:partner_multi_relation_tabs.menu_res_partner_tab
msgid "Relation Tabs"
msgstr "Connectie tabs"
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "Select partner type and category for tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "Select specific partners to have this tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_all_tab_id
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_selection_tab_id
msgid "Show relation on tab"
msgstr "Toon connectie op tab"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_tab_right_id
msgid "Tab for inverse relation"
msgstr "Tab voor de omgekeerde relatie"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_tab_left_id
msgid "Tab for this relation"
msgstr "Tab voor deze relatie"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_relation_type_tab_right_id
msgid "Tab in which inverse relations will be visible on partner."
msgstr "Tab waar de omgekeerde connecties zichtbaar zullen zijn op de relatie."
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_relation_type_tab_left_id
msgid "Tab in which these relations will be visible on partner."
msgstr "Tab waarin deze connecties zichtbaar zullen zijn op de relaties."
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_tab
msgid "Tabs to add to partner"
msgstr "Tab die aan de relatie wordt toegevoegd"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_partner_ids
msgid ""
"This tab will only show for certain partners.\n"
"Do not combine this with selection for contact type or category."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_partner_category_id
msgid "Valid for partner category"
msgstr "Geldig voor relatiecategorie"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_contact_type
msgid "Valid for partner type"
msgstr "Geldig voor type relatie"
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_name
msgid "Will provide title for tab in user language"
msgstr "Wordt gebruikt voor titel van tabblad in de taal van de gebruiker"
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_tab.py:49
#, python-format
msgid "You can not both specify partner_ids and other criteria."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_company_has_ceo
msgid "has ceo"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_committee_has_chairperson
msgid "has chairperson"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_organisation_has_department
msgid "has department"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_company_has_ceo
msgid "is ceo of"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_committee_has_chairperson
msgid "is chairperson of"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_organisation_has_department
msgid "is department of"
msgstr ""
#~ msgid "Adding field %s to res.partner nodel."
#~ msgstr "Veld %s wordt toegevoegd aan res.partner model."
#~ msgid "Updating field %s in res.partner nodel."
#~ msgstr "Veld %s op res.partner model wordt bijgewerkt."
#~ msgid "deleting field %s from res.partner nodel."
#~ msgstr "verwijderen veld % van res.partner model."

264
partner_multi_relation_tabs/i18n/partner_multi_relation_tabs.pot

@ -0,0 +1,264 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_multi_relation_tabs
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_all
msgid "All (non-inverse + inverse) relations between partners"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_type_selection
msgid "All relation types"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_code
msgid "Code"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_board
msgid "Company executive board"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner
msgid "Contact"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:33
#, python-format
msgid "Contact type left not compatible with left tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:53
#, python-format
msgid "Contact type right not compatible with right tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_create_uid
msgid "Created by"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_create_date
msgid "Created on"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_department
msgid "Department"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_display_name
msgid "Display Name"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_functionary
msgid "Functionary"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "General"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.category,name:partner_multi_relation_tabs.category_government
msgid "Government"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_committee
msgid "Government committee"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_id
msgid "ID"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_code
msgid "Language independent code for tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab___last_update
msgid "Last Modified on"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_write_uid
msgid "Last Updated by"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_write_date
msgid "Last Updated on"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_name
msgid "Name"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_departments
msgid "Our departments"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/tablib/tab.py:56
#, python-format
msgid "Partner"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_relation_type
msgid "Partner Relation Type"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:38
#, python-format
msgid "Partner category left not compatible with left tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:58
#, python-format
msgid "Partner category right not compatible with right tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_partner_ids
msgid "Partners with this tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.tab,name:partner_multi_relation_tabs.tab_positions
msgid "Positions held"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.actions.act_window,name:partner_multi_relation_tabs.action_res_partner_tab
#: model:ir.ui.menu,name:partner_multi_relation_tabs.menu_res_partner_tab
msgid "Relation Tabs"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "Select partner type and category for tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.ui.view,arch_db:partner_multi_relation_tabs.form_res_partner_tab
msgid "Select specific partners to have this tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_all_tab_id
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_selection_tab_id
msgid "Show relation on tab"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_tab_right_id
msgid "Tab for inverse relation"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_relation_type_tab_left_id
msgid "Tab for this relation"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_relation_type_tab_right_id
msgid "Tab in which inverse relations will be visible on partner."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_relation_type_tab_left_id
msgid "Tab in which these relations will be visible on partner."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model,name:partner_multi_relation_tabs.model_res_partner_tab
msgid "Tabs to add to partner"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_partner_ids
msgid "This tab will only show for certain partners.\n"
"Do not combine this with selection for contact type or category."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_partner_category_id
msgid "Valid for partner category"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,field_description:partner_multi_relation_tabs.field_res_partner_tab_contact_type
msgid "Valid for partner type"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:ir.model.fields,help:partner_multi_relation_tabs.field_res_partner_tab_name
msgid "Will provide title for tab in user language"
msgstr ""
#. module: partner_multi_relation_tabs
#: code:addons/partner_multi_relation_tabs/models/res_partner_tab.py:49
#, python-format
msgid "You can not both specify partner_ids and other criteria."
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_company_has_ceo
msgid "has ceo"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_committee_has_chairperson
msgid "has chairperson"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name:partner_multi_relation_tabs.relation_type_organisation_has_department
msgid "has department"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_company_has_ceo
msgid "is ceo of"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_committee_has_chairperson
msgid "is chairperson of"
msgstr ""
#. module: partner_multi_relation_tabs
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_tabs.relation_type_organisation_has_department
msgid "is department of"
msgstr ""

6
partner_multi_relation_tabs/models/__init__.py

@ -0,0 +1,6 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import res_partner_tab
from . import res_partner_relation_type
from . import res_partner_relation_type_selection
from . import res_partner_relation_all
from . import res_partner

100
partner_multi_relation_tabs/models/res_partner.py

@ -0,0 +1,100 @@
# Copyright 2014-2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=no-member
import logging
from lxml import etree
from odoo import api, fields, models
_logger = logging.getLogger(__name__) # pylint: disable=invalid-name
class ResPartner(models.Model):
_inherit = 'res.partner'
@api.multi
def browse(self, arg=None, prefetch=None):
for tab in self._get_tabs():
fieldname = tab.get_fieldname()
if fieldname not in self._fields:
# Check this for performance reasons.
self.add_field(tab)
return super(ResPartner, self).browse(arg=arg, prefetch=prefetch)
@api.model
def fields_view_get(
self, view_id=None, view_type='form', toolbar=False,
submenu=False):
"""Override to add relation tabs to form."""
result = super(ResPartner, self).fields_view_get(
view_id=view_id, view_type=view_type, toolbar=toolbar,
submenu=submenu)
if view_type != 'form' or self.env.context.get('check_view_ids'):
return result
view = etree.fromstring(result['arch'])
extra_fields = self._add_tab_pages(view)
view_model = self.env['ir.ui.view']
result['arch'], original_fields = view_model.postprocess_and_fields(
self._name, view, result['view_id'])
for fieldname in extra_fields:
result['fields'][fieldname] = original_fields[fieldname]
return result
def _add_tab_pages(self, view):
"""Adds the relevant tabs to the partner's formview."""
# pylint: disable=no-member
def add_invisible_extra_field(view, extra_fields, fieldname):
"""Add invisible field to view."""
view.append(
etree.Element('field', name=fieldname, invisible='True'))
extra_fields.append(fieldname)
last_page_nodes = view.xpath('//page[last()]')
if not last_page_nodes:
# Nothing to do if form contains no pages/tabs.
return []
extra_fields = []
if not view.xpath('//field[@name="id"]'):
add_invisible_extra_field(view, extra_fields, 'id')
last_page = last_page_nodes[0]
for tab in self._get_tabs(): # get all tabs
self.add_field(tab)
add_invisible_extra_field(
view, extra_fields, tab.get_visible_fieldname())
extra_fields.append(tab.get_fieldname())
tab_page = tab.create_page()
last_page.addnext(tab_page)
last_page = tab_page # Keep ordering of tabs
return extra_fields
@api.depends('is_company', 'category_id')
def _compute_tabs_visibility(self):
"""Compute for all tabs wether they should be visible."""
for tab in self._get_tabs(): # get all tabs
for this in self:
this[tab.get_visible_fieldname()] = \
tab.compute_visibility(this)
def _get_tabs(self):
tab_model = self.env['res.partner.tab']
return tab_model.get_tabs()
def add_field(self, tab):
"""Add tab field to model.
Will replace existing field if already present.
"""
# Visible field determines wether first field will be visible.
# This is because domains on many2many no longer work in 9.0
# and above.
visible_field = fields.Boolean(compute='_compute_tabs_visibility')
self._add_field(tab.get_visible_fieldname(), visible_field)
if visible_field not in self._field_computed:
self._field_computed[visible_field] = [visible_field]
tab_field = fields.One2many(
comodel_name='res.partner.relation.all',
inverse_name='this_partner_id',
domain=[('tab_id', '=', tab.tab_record.id)],
string=tab.tab_record.name)
self._add_field(tab.get_fieldname(), tab_field)

56
partner_multi_relation_tabs/models/res_partner_relation_all.py

@ -0,0 +1,56 @@
# Copyright 2014-2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
class ResPartnerRelationAll(models.AbstractModel):
"""Abstract model to show each relation from two sides."""
_inherit = 'res.partner.relation.all'
tab_id = fields.Many2one(
comodel_name='res.partner.tab',
string='Show relation on tab',
readonly=True,
)
def _get_additional_view_fields(self):
"""Add tab_id to view fields."""
# pylint: disable=no-member
return ','.join([
super(ResPartnerRelationAll, self)._get_additional_view_fields(),
"CASE"
" WHEN NOT bas.is_inverse"
" THEN lefttab.id"
" ELSE righttab.id"
" END as tab_id"])
def _get_additional_tables(self):
"""Add res_partner_tab table to view."""
# pylint: disable=no-member
return ' '.join([
super(ResPartnerRelationAll, self)._get_additional_tables(),
"LEFT OUTER JOIN res_partner_tab lefttab"
" ON typ.tab_left_id = lefttab.id",
"LEFT OUTER JOIN res_partner_tab righttab"
" ON typ.tab_right_id = righttab.id"])
@api.onchange(
'this_partner_id',
'other_partner_id',
)
def onchange_partner_id(self):
"""Add tab if needed to type_selection_id domain.
This method makes sure that when a relation is added to a tab,
it is with a relation type meant to be placed on that tab.
"""
# pylint: disable=no-member
result = super(ResPartnerRelationAll, self).onchange_partner_id()
if 'default_tab_id' in self.env.context:
result['domain'] = result['domain'] if 'domain' in result else {}
result['domain']['type_selection_id'] = \
result['domain']['type_selection_id'] \
if 'type_selection_id' in result['domain'] else {}
result['domain']['type_selection_id'].append(
('tab_id', '=', self.env.context['default_tab_id']))
return result

59
partner_multi_relation_tabs/models/res_partner_relation_type.py

@ -0,0 +1,59 @@
# Copyright 2014-2017 Therp BV <https://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=no-self-use
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class ResPartnerRelationType(models.Model):
# pylint: disable=too-few-public-methods
_inherit = 'res.partner.relation.type'
tab_left_id = fields.Many2one(
comodel_name='res.partner.tab',
string='Tab for this relation',
help="Tab in which these relations will be visible on partner.")
tab_right_id = fields.Many2one(
comodel_name='res.partner.tab',
string='Tab for inverse relation',
help="Tab in which inverse relations will be visible on partner.")
@api.multi
@api.constrains(
'contact_type_left',
'partner_category_left',
'tab_left_id')
def _check_tab_left(self):
"""Conditions for left partner should be consistent with tab."""
for rec in self:
if not rec.tab_left_id:
continue
tab_contact_type = rec.tab_left_id.contact_type
if tab_contact_type and tab_contact_type != rec.contact_type_left:
raise ValidationError(_(
"Contact type left not compatible with left tab"))
tab_partner_category_id = rec.tab_left_id.partner_category_id
if tab_partner_category_id and \
tab_partner_category_id != rec.partner_category_left:
raise ValidationError(_(
"Partner category left not compatible with left tab"))
@api.multi
@api.constrains(
'contact_type_right',
'partner_category_right',
'tab_right_id')
def _check_tab_right(self):
"""Conditions for right partner should be consistent with tab."""
for rec in self:
if not rec.tab_right_id:
continue
tab_contact_type = rec.tab_right_id.contact_type
if tab_contact_type and tab_contact_type != rec.contact_type_right:
raise ValidationError(_(
"Contact type right not compatible with right tab"))
tab_partner_category_id = rec.tab_right_id.partner_category_id
if tab_partner_category_id and \
tab_partner_category_id != rec.partner_category_right:
raise ValidationError(_(
"Partner category right not compatible with right tab"))

35
partner_multi_relation_tabs/models/res_partner_relation_type_selection.py

@ -0,0 +1,35 @@
# Copyright 2013-2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class ResPartnerRelationTypeSelection(models.Model):
"""Virtual relation types"""
_inherit = 'res.partner.relation.type.selection'
tab_id = fields.Many2one(
comodel_name='res.partner.tab',
string='Show relation on tab',
readonly=True,
)
def _get_additional_view_fields(self):
"""Add tab_id to fields in view."""
return ','.join([
super(ResPartnerRelationTypeSelection, self)
._get_additional_view_fields(),
"CASE"
" WHEN NOT bas.is_inverse"
" THEN lefttab.id"
" ELSE righttab.id"
" END as tab_id"])
def _get_additional_tables(self):
"""Add two links to res_partner_tab."""
return ' '.join([
super(ResPartnerRelationTypeSelection, self)
._get_additional_tables(),
"LEFT OUTER JOIN res_partner_tab lefttab"
" ON typ.tab_left_id = lefttab.id",
"LEFT OUTER JOIN res_partner_tab righttab"
" ON typ.tab_right_id = righttab.id"])

95
partner_multi_relation_tabs/models/res_partner_tab.py

@ -0,0 +1,95 @@
# Copyright 2017-2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from ..tablib import Tab
class ResPartnerTab(models.Model):
"""Model that defines relation types that might exist between partners"""
_name = 'res.partner.tab'
_description = 'Tabs to add to partner'
_order = 'name'
@api.model
def get_partner_types(self):
"""Partner types are defined by model res.partner.relation.type."""
# pylint: disable=no-self-use
rprt_model = self.env['res.partner.relation.type']
return rprt_model.get_partner_types()
code = fields.Char(
string='Code',
required=True,
help="Language independent code for tab")
name = fields.Char(
string='Name',
required=True,
translate=True,
help="Will provide title for tab in user language")
contact_type = fields.Selection(
selection='get_partner_types',
string='Valid for partner type')
partner_category_id = fields.Many2one(
comodel_name='res.partner.category',
string='Valid for partner category')
partner_ids = fields.Many2many(
comodel_name='res.partner',
string="Partners with this tab",
help="This tab will only show for certain partners.\n"
"Do not combine this with selection for contact type or"
" category.")
@api.constrains('contact_type', 'partner_category_id', 'partner_ids')
def _check_partner_ids(self):
"""If partner_ids filled, other domain fields should be empty."""
if self.partner_ids and \
(self.contact_type or self.partner_category_id):
raise ValidationError(_(
"You can not both specify partner_ids and other criteria."))
@api.multi
def update_types(self, vals=None):
"""Update types on write or unlink.
If we have no vals, assume unlink.
"""
if vals:
contact_type = vals.get('contact_type', False)
partner_category_id = vals.get('partner_category_id', False)
type_model = self.env['res.partner.relation.type']
for this in self:
for tab_side in ('left', 'right'):
side_tab = 'tab_%s_id' % tab_side
tab_using = type_model.search([(side_tab, '=', this.id)])
for relation_type in tab_using:
type_value = relation_type['contact_type_%s' % tab_side]
category_value = \
relation_type['partner_category_%s' % tab_side]
if (not vals or
(contact_type and contact_type != type_value) or
(partner_category_id and
partner_category_id != category_value.id)):
relation_type.write({side_tab: False})
@api.multi
def write(self, vals):
"""Remove tab from types no longer satifying criteria."""
if vals.get('contact_type', False) or \
vals.get('partner_category_id', False):
self.update_types(vals)
result = super(ResPartnerTab, self).write(vals)
return result
@api.multi
def unlink(self):
"""Unlink should first remove references."""
self.update_types()
return super(ResPartnerTab, self).unlink()
@api.model
def get_tabs(self):
"""Convert information on tabs in database to array of objects."""
tabs = [Tab(tab_record) for tab_record in self.search([])]
return tabs

5
partner_multi_relation_tabs/readme/CONTRIBUTORS.rst

@ -0,0 +1,5 @@
* Holger Brunn <hbrunn@therp.nl>
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
* Stéphane Bidoul <stephane.bidoul@acsone.eu>
* Ronald Portier <ronald@therp.nl>
* George Daramouskas <gdaramouskas@therp.nl>

9
partner_multi_relation_tabs/readme/DESCRIPTION.rst

@ -0,0 +1,9 @@
This module adds the possibility to show certain partner relations in a
tab on the partner form, in addition to in the list of all relations.
This can be useful if certain relation types are regularly used and should
be overseeable at a glace.
For instance you can make a tab named 'board' that will show all the board
members of a company, by showing the relations of types ceo, cto, cfo and
board member.

78
partner_multi_relation_tabs/readme/USAGE.rst

@ -0,0 +1,78 @@
Relation Type Tabs
~~~~~~~~~~~~~~~~~~
Before being able to show certain types of relations on a tab in the partner
form, you will have to define the tab.
Do that in Contacts / Relations / Relation Tabs.
.. image:: ../static/description/partner_multi_relation_tabs-tab-configuration.png
If you specify nothing, the tab will be shown on all partner forms that have
tabs (page elements). Normally you will select to show the tab only on
partners that are companies/organisations, or only for persons. You can also
select a category to further limit for which partners the tab wil be shown.
The possibility exists to show a tab only on specific partners. For instance
on your own company partner.
Relation Types
~~~~~~~~~~~~~~
In configuring the relation types, you can select which type of relation will
be shown on which tab. It is possible to show multiple types on one tab.
Do that in Contacts / Relations / Relation Types.
For example on a 'executive board' tab, you might want to show the CEO of a
company, but also the CFO, the CTO and normal board members.
You might specify a tab for both the 'left side' of a relation, as for the
'right side' or inverse relation. So a relation 'company has ceo', with
inverse type 'person is ceo of' might specify the 'board' tab for the
company type of the relation, but possibly a 'positions held' tab for the
person side of the relation, so on the partner form of a person you see in
one tab all positions or functions a person has, regardless in which company
or organisation.
For each side of a relation, the partner contact type and the partner category
must be consistent with those specified for the tab.
.. image:: ../static/description/partner_multi_relation_tabs-relation-type-configuration.png
Partner Form
~~~~~~~~~~~~
The partner form will contain extra tab pages, for each tab that is
appropiate for that partner. So a company partner does not show the tabs that
are meant for persons and vice versa. Also tabs meant for partners with
a certain category/label will only show if partners have that label.
When adding relations on a tab, only relation types appropiate for that tab
can be selected.
Example of adding a relation:
.. image:: ../static/description/partner_multi_relation_tabs-partner-edit.png
Example of a filled out board tab:
.. image:: ../static/description/partner_multi_relation_tabs-partner-display.png
Deleting tabs
~~~~~~~~~~~~~
When a tab is deleted, this will in no way effect the existing relations.
However the references on the relation types to the deleted tabs will also be
cleared.
Searching Relations by Tab
~~~~~~~~~~~~~~~~~~~~~~~~~~
You can search relations with the tab on which they are shown. For instance
to find all board members.
Do that in Contacts / Relations / Relations.
.. image:: ../static/description/partner_multi_relation_tabs-relation-search.png

3
partner_multi_relation_tabs/security/ir.model.access.csv

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
read_res_partner_tab,read_res_partner_tab,model_res_partner_tab,,1,0,0,0
crud_res_partner_tab,crud_res_partner_tab,model_res_partner_tab,base.group_partner_manager,1,1,1,1

BIN
partner_multi_relation_tabs/static/description/icon.png

After

Width: 90  |  Height: 90  |  Size: 18 KiB

497
partner_multi_relation_tabs/static/description/index.html

@ -0,0 +1,497 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>Show partner relations in own tab</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="show-partner-relations-in-own-tab">
<h1 class="title">Show partner relations in own tab</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/partner-contact/tree/12.0/partner_multi_relation_tabs"><img alt="OCA/partner-contact" src="https://img.shields.io/badge/github-OCA%2Fpartner--contact-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/partner-contact-12-0/partner-contact-12-0-partner_multi_relation_tabs"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/134/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module adds the possibility to show certain partner relations in a
tab on the partner form, in addition to in the list of all relations.</p>
<p>This can be useful if certain relation types are regularly used and should
be overseeable at a glace.</p>
<p>For instance you can make a tab named ‘board’ that will show all the board
members of a company, by showing the relations of types ceo, cto, cfo and
board member.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a><ul>
<li><a class="reference internal" href="#relation-type-tabs" id="id2">Relation Type Tabs</a></li>
<li><a class="reference internal" href="#relation-types" id="id3">Relation Types</a></li>
<li><a class="reference internal" href="#partner-form" id="id4">Partner Form</a></li>
<li><a class="reference internal" href="#deleting-tabs" id="id5">Deleting tabs</a></li>
<li><a class="reference internal" href="#searching-relations-by-tab" id="id6">Searching Relations by Tab</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id7">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id8">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id9">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id10">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id11">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<div class="section" id="relation-type-tabs">
<h2><a class="toc-backref" href="#id2">Relation Type Tabs</a></h2>
<p>Before being able to show certain types of relations on a tab in the partner
form, you will have to define the tab.</p>
<p>Do that in Contacts / Relations / Relation Tabs.</p>
<img alt="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-tab-configuration.png" src="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-tab-configuration.png" />
<p>If you specify nothing, the tab will be shown on all partner forms that have
tabs (page elements). Normally you will select to show the tab only on
partners that are companies/organisations, or only for persons. You can also
select a category to further limit for which partners the tab wil be shown.</p>
<p>The possibility exists to show a tab only on specific partners. For instance
on your own company partner.</p>
</div>
<div class="section" id="relation-types">
<h2><a class="toc-backref" href="#id3">Relation Types</a></h2>
<p>In configuring the relation types, you can select which type of relation will
be shown on which tab. It is possible to show multiple types on one tab.</p>
<p>Do that in Contacts / Relations / Relation Types.</p>
<p>For example on a ‘executive board’ tab, you might want to show the CEO of a
company, but also the CFO, the CTO and normal board members.</p>
<p>You might specify a tab for both the ‘left side’ of a relation, as for the
‘right side’ or inverse relation. So a relation ‘company has ceo’, with
inverse type ‘person is ceo of’ might specify the ‘board’ tab for the
company type of the relation, but possibly a ‘positions held’ tab for the
person side of the relation, so on the partner form of a person you see in
one tab all positions or functions a person has, regardless in which company
or organisation.</p>
<p>For each side of a relation, the partner contact type and the partner category
must be consistent with those specified for the tab.</p>
<img alt="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-type-configuration.png" src="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-type-configuration.png" />
</div>
<div class="section" id="partner-form">
<h2><a class="toc-backref" href="#id4">Partner Form</a></h2>
<p>The partner form will contain extra tab pages, for each tab that is
appropiate for that partner. So a company partner does not show the tabs that
are meant for persons and vice versa. Also tabs meant for partners with
a certain category/label will only show if partners have that label.</p>
<p>When adding relations on a tab, only relation types appropiate for that tab
can be selected.</p>
<p>Example of adding a relation:</p>
<img alt="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-edit.png" src="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-edit.png" />
<p>Example of a filled out board tab:</p>
<img alt="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-display.png" src="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-display.png" />
</div>
<div class="section" id="deleting-tabs">
<h2><a class="toc-backref" href="#id5">Deleting tabs</a></h2>
<p>When a tab is deleted, this will in no way effect the existing relations.</p>
<p>However the references on the relation types to the deleted tabs will also be
cleared.</p>
</div>
<div class="section" id="searching-relations-by-tab">
<h2><a class="toc-backref" href="#id6">Searching Relations by Tab</a></h2>
<p>You can search relations with the tab on which they are shown. For instance
to find all board members.</p>
<p>Do that in Contacts / Relations / Relations.</p>
<img alt="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-search.png" src="https://raw.githubusercontent.com/OCA/partner-contact/12.0/partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-search.png" />
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id7">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/partner-contact/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/partner-contact/issues/new?body=module:%20partner_multi_relation_tabs%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id8">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id9">Authors</a></h2>
<ul class="simple">
<li>Therp BV</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id10">Contributors</a></h2>
<ul class="simple">
<li>Holger Brunn &lt;<a class="reference external" href="mailto:hbrunn&#64;therp.nl">hbrunn&#64;therp.nl</a>&gt;</li>
<li>Alexandre Fayolle &lt;<a class="reference external" href="mailto:alexandre.fayolle&#64;camptocamp.com">alexandre.fayolle&#64;camptocamp.com</a>&gt;</li>
<li>Stéphane Bidoul &lt;<a class="reference external" href="mailto:stephane.bidoul&#64;acsone.eu">stephane.bidoul&#64;acsone.eu</a>&gt;</li>
<li>Ronald Portier &lt;<a class="reference external" href="mailto:ronald&#64;therp.nl">ronald&#64;therp.nl</a>&gt;</li>
<li>George Daramouskas &lt;<a class="reference external" href="mailto:gdaramouskas&#64;therp.nl">gdaramouskas&#64;therp.nl</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id11">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/partner-contact/tree/12.0/partner_multi_relation_tabs">OCA/partner-contact</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

BIN
partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-display.png

After

Width: 815  |  Height: 566  |  Size: 42 KiB

BIN
partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-partner-edit.png

After

Width: 815  |  Height: 566  |  Size: 35 KiB

BIN
partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-search.png

After

Width: 815  |  Height: 566  |  Size: 23 KiB

BIN
partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-relation-type-configuration.png

After

Width: 815  |  Height: 566  |  Size: 35 KiB

BIN
partner_multi_relation_tabs/static/description/partner_multi_relation_tabs-tab-configuration.png

After

Width: 815  |  Height: 566  |  Size: 28 KiB

2
partner_multi_relation_tabs/tablib/__init__.py

@ -0,0 +1,2 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from .tab import Tab

83
partner_multi_relation_tabs/tablib/tab.py

@ -0,0 +1,83 @@
# Copyright 2014-2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import logging
from lxml import etree
from odoo import _
from odoo.osv.orm import transfer_modifiers_to_node
_logger = logging.getLogger(__name__) # pylint: disable=invalid-name
NAME_PREFIX = 'relation_ids_tab'
class Tab(object):
"""Encapsulate the information on a tab in the database."""
def __init__(self, tab_record):
"""Create tab from tab_record.
In this version tab_record can be assumed to be a partner.relation.tab.
"""
self.tab_record = tab_record
self.name = tab_record.code
def get_fieldname(self):
return '%s_%s' % (NAME_PREFIX, self.tab_record.id)
def get_visible_fieldname(self):
return '%s_visible' % self.get_fieldname()
def create_page(self):
tab_page = etree.Element('page')
self._set_page_attrs(tab_page)
field = etree.Element(
'field',
name=self.get_fieldname(),
context='{'
'"default_this_partner_id": id,'
'"default_tab_id": %d,'
'"active_test": False}' % self.tab_record.id)
tab_page.append(field)
tree = etree.Element('tree', editable='bottom')
field.append(tree)
# Now add fields for the editable tree view in the tab.
type_field = etree.Element(
'field',
name='type_selection_id',
widget='many2one_clickable')
type_field.set('domain', repr([('tab_id', '=', self.tab_record.id)]))
type_field.set('options', repr({'no_create': True}))
tree.append(type_field)
other_partner_field = etree.Element(
'field',
string=_('Partner'),
name='other_partner_id',
widget='many2one_clickable')
other_partner_field.set('options', repr({'no_create': True}))
tree.append(other_partner_field)
tree.append(etree.Element('field', name='date_start'))
tree.append(etree.Element('field', name='date_end'))
return tab_page
def _set_page_attrs(self, tab_page):
tab_page.set('string', self.tab_record.name)
attrs = {'invisible': [(self.get_visible_fieldname(), '=', False)]}
tab_page.set('attrs', repr(attrs))
transfer_modifiers_to_node(attrs, tab_page)
def compute_visibility(self, partner):
"""Compute visibility, dependent on partner and conditions."""
tab = self.tab_record
if tab.partner_ids:
return partner in tab.partner_ids
if tab.contact_type:
is_company_tab = tab.contact_type == 'c'
if partner.is_company != is_company_tab:
return False
if tab.partner_category_id:
if tab.partner_category_id not in partner.category_id:
return False
return True

4
partner_multi_relation_tabs/tests/__init__.py

@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import common
from . import test_partner_tabs
from . import test_tab

50
partner_multi_relation_tabs/tests/common.py

@ -0,0 +1,50 @@
# Copyright 2014-2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.tests import common
class TestCommon(common.SingleTransactionCase):
# pylint: disable=too-many-instance-attributes
post_install = True
def setUp(self):
"""Create common objects for tab tests."""
# pylint: disable=invalid-name
super(TestCommon, self).setUp()
self.tab_model = self.env['res.partner.tab']
self.type_model = self.env['res.partner.relation.type']
self.partner_model = self.env['res.partner']
self.relation_model = self.env['res.partner.relation']
# Categories.
self.category_government = self.env.ref(
'partner_multi_relation_tabs.category_government')
self.category_functionary = self.env.ref(
'partner_multi_relation_tabs.category_functionary')
self.category_department = self.env.ref(
'partner_multi_relation_tabs.category_department')
# Tabs.
self.tab_committee = self.env.ref(
'partner_multi_relation_tabs.tab_committee')
self.tab_board = self.env.ref(
'partner_multi_relation_tabs.tab_board')
self.tab_positions = self.env.ref(
'partner_multi_relation_tabs.tab_positions')
self.tab_departments = self.env.ref(
'partner_multi_relation_tabs.tab_departments')
# Types.
self.type_chairperson = self.env.ref(
'partner_multi_relation_tabs'
'.relation_type_committee_has_chairperson')
self.type_ceo = self.env.ref(
'partner_multi_relation_tabs'
'.relation_type_company_has_ceo')
# Partners.
self.partner_big_company = self.env.ref(
'partner_multi_relation_tabs.partner_big_company')
self.partner_important_person = self.env.ref(
'partner_multi_relation_tabs.partner_important_person')
self.partner_common_person = self.env.ref(
'partner_multi_relation_tabs.partner_common_person')
# Relations.
self.relation_company_ceo = self.env.ref(
'partner_multi_relation_tabs.relation_company_ceo')

157
partner_multi_relation_tabs/tests/test_partner_tabs.py

@ -0,0 +1,157 @@
# Copyright 2014-2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from lxml import etree
from odoo.exceptions import ValidationError
from . import common
from ..tablib import Tab
class TestPartnerTabs(common.TestCommon):
post_install = True
def test_create_tab(self):
self.assertTrue(bool(self.tab_board))
tab_obj = Tab(self.tab_board)
# fields_view_get should force the creation of the new tabs.
view_partner_form = self.env.ref('base.view_partner_form')
view = self.partner_model.with_context().fields_view_get(
view_id=view_partner_form.id, view_type='form')
# The form view for partner should now also contain field 'id'.
tree = etree.fromstring(view['arch'])
field = tree.xpath('//field[@name="id"]')
self.assertTrue(field, 'Id field does not exist.')
# There should now be a field in res_partner for the new tab.
fieldname = tab_obj.get_fieldname()
self.assertTrue(fieldname in self.partner_model._fields)
# And we should have a field for the tab:
field = tree.xpath('//field[@name="%s"]' % fieldname)
self.assertTrue(
field,
'Tab field %s does not exist in %s.' %
(fieldname, etree.tostring(tree)))
# There should be no effect on the tree view:
view = self. partner_model.with_context().fields_view_get(
view_type='tree')
tree = etree.fromstring(view['arch'])
field = tree.xpath('//field[@name="%s"]' % fieldname)
self.assertFalse(
field,
'Tab field %s should not exist in %s.' %
(fieldname, etree.tostring(tree)))
def test_view_without_pages(self):
"""Check that _add_tab_pages does not effect view without pages."""
# pylint: disable=protected-access
view = etree.Element('view')
extra_fields = self.partner_model._add_tab_pages(view)
self.assertFalse(extra_fields)
def test_tab_modifications(self):
tab_executive = self.tab_model.create({
'code': 'executive',
'name': 'Executive members'})
self.assertTrue(bool(tab_executive))
type_chairperson = self.type_model.create({
'name': 'has chairperson',
'name_inverse': 'is chairperson for',
'contact_type_left': 'p', # This emulates a user mistake.
'contact_type_right': 'p',
'tab_left_id': tab_executive.id})
self.assertTrue(bool(type_chairperson))
# If we change tab now to be only valid on company partners
# the tab_left_id field should be cleared from the type:
tab_executive.write({'contact_type': 'c'})
self.assertFalse(type_chairperson.tab_left_id.id)
# Trying to set the tab back on type should be impossible:
with self.assertRaises(ValidationError):
type_chairperson.write({'tab_left_id': tab_executive.id})
# We should be able to change tab, if also changing contact type.
type_chairperson.write({
'contact_type_left': 'c',
'tab_left_id': tab_executive.id})
self.assertEqual(
type_chairperson.tab_left_id.id,
tab_executive.id)
# Unlinking the tab should reset the tab_left_id on relation type.
tab_executive.unlink()
self.assertEqual(
type_chairperson.tab_left_id.id,
False)
# It should not be possible to add category or contact type to as
# selection criteria to a tab meant for specific partners.
with self.assertRaises(ValidationError):
self.tab_departments.write({'contact_type': 'c'})
with self.assertRaises(ValidationError):
self.tab_departments.write({
'partner_category_id': self.category_government.id})
def test_type_modifications(self):
self.assertTrue(bool(self.tab_board))
self.assertTrue(bool(self.tab_positions))
self.assertTrue(bool(self.type_chairperson))
# Trying to clear either category should raise ValidationError:
with self.assertRaises(ValidationError):
self.type_chairperson.write({'partner_category_left': False})
with self.assertRaises(ValidationError):
self.type_chairperson.write({'partner_category_right': False})
# Trying to clear either contact type should raise ValidationError:
with self.assertRaises(ValidationError):
self.type_chairperson.write({'contact_type_left': False})
with self.assertRaises(ValidationError):
self.type_chairperson.write({'contact_type_right': False})
def test_relations(self):
"""Test relations shown on tab."""
relation_all_model = self.env['res.partner.relation.all']
self.assertTrue(bool(self.tab_board))
self.assertTrue(bool(self.type_ceo))
self.assertTrue(bool(self.partner_big_company))
self.assertTrue(bool(self.partner_important_person))
self.assertTrue(bool(self.relation_company_ceo))
# Now we should be able to find the relation with the tab_id:
board_partners = relation_all_model.search([
('tab_id', '=', self.tab_board.id)])
self.assertTrue(bool(board_partners))
self.assertIn(
self.partner_big_company,
[relation.this_partner_id for relation in board_partners])
# We should find the company on the partner through tab field:
tab_obj = Tab(self.tab_board)
fieldname = tab_obj.get_fieldname()
self.assertTrue(fieldname in self.partner_model._fields)
board_partners = self.partner_big_company[fieldname]
self.assertEqual(len(board_partners), 1)
self.assertEqual(
board_partners.other_partner_id.id,
self.partner_important_person.id)
# When adding a new relation on a tab, type must be for tab.
onchange_result = board_partners.with_context(
default_tab_id=self.tab_board.id
).onchange_partner_id()
self.assertTrue(onchange_result)
self.assertIn('domain', onchange_result)
self.assertIn('type_selection_id', onchange_result['domain'])
self.assertEqual(
onchange_result['domain']['type_selection_id'][-1],
('tab_id', '=', self.tab_board.id))
def test_compute_visibility(self):
"""Check the computation of visibility on partners."""
# pylint: disable=protected-access
main_partner = self.env.ref('base.main_partner')
main_partner._compute_tabs_visibility()
tab_obj = Tab(self.tab_departments)
fieldname = tab_obj.get_fieldname()
visible_fieldname = tab_obj.get_visible_fieldname()
self.assertIn(visible_fieldname, main_partner._fields)
self.assertIn(fieldname, main_partner._fields)
self.assertEqual(main_partner[visible_fieldname], True)
department_relations = main_partner[fieldname]
self.assertTrue(len(department_relations) >= 1)
departments = [
relation.other_partner_id for relation in department_relations]
for department in departments:
self.assertIn(
self.category_department, department.category_id)

39
partner_multi_relation_tabs/tests/test_tab.py

@ -0,0 +1,39 @@
# Copyright 2018 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import common
from ..tablib import Tab
class TestTab(common.TestCommon):
def test_create_page(self):
self.assertTrue(bool(self.tab_board))
tab_obj = Tab(self.tab_board)
page = tab_obj.create_page()
# And we should have a field for (amongst others) selection_type_id.
field = page.xpath('//field[@name="type_selection_id"]')
self.assertTrue(field, 'Field selection_type_id not in page.')
def test_visibility(self):
"""Tab positions should be shown for functionaries, but not others."""
self.assertTrue(bool(self.tab_positions))
self.assertTrue(bool(self.partner_important_person))
self.assertTrue(bool(self.partner_common_person))
tab_obj = Tab(self.tab_positions)
self.assertTrue(
tab_obj.compute_visibility(self.partner_important_person),
'Positions tab should be visible for functionary.')
self.assertFalse(
tab_obj.compute_visibility(self.partner_common_person),
'Positions tab should not be visible for non-functionary.')
# Tab for departments should only be visible for main partner
self.assertTrue(bool(self.tab_departments))
self.assertTrue(bool(self.partner_big_company))
tab_obj = Tab(self.tab_departments)
self.assertTrue(
tab_obj.compute_visibility(self.env.ref('base.main_partner')),
'Department tab should be visible for main partner.')
self.assertFalse(
tab_obj.compute_visibility(self.partner_big_company),
'Department tab should not be visible for other partners.')

18
partner_multi_relation_tabs/views/menu.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<act_window
id="action_res_partner_tab"
res_model="res.partner.tab"
view_mode="tree,form"
name="Relation Tabs"
/>
<menuitem
id="menu_res_partner_tab"
parent="partner_multi_relation.menu_res_partner_relation"
action="action_res_partner_tab"
sequence="80"
/>
</odoo>

17
partner_multi_relation_tabs/views/res_partner_relation_all.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="search_res_partner_relation_all" model="ir.ui.view">
<field name="model">res.partner.relation.all</field>
<field
name="inherit_id"
ref="partner_multi_relation.search_res_partner_relation_all"
/>
<field name="arch" type="xml">
<field name="type_selection_id" position="after">
<field name="tab_id"/>
</field>
</field>
</record>
</odoo>

20
partner_multi_relation_tabs/views/res_partner_relation_type.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="form_res_partner_relation_type" model="ir.ui.view">
<field name="model">res.partner.relation.type</field>
<field
name="inherit_id"
ref="partner_multi_relation.form_res_partner_relation_type"
/>
<field name="arch" type="xml">
<field name="partner_category_left" position="after">
<field name="tab_left_id" />
</field>
<field name="partner_category_right" position="after">
<field name="tab_right_id" />
</field>
</field>
</record>
</odoo>

44
partner_multi_relation_tabs/views/res_partner_tab.xml

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="tree_res_partner_tab" model="ir.ui.view">
<field name="model">res.partner.tab</field>
<field type="xml" name="arch">
<tree>
<field name="code" />
<field name="name" />
</tree>
</field>
</record>
<record id="form_res_partner_tab" model="ir.ui.view">
<field name="model">res.partner.tab</field>
<field type="xml" name="arch">
<form>
<group colspan="6" col="4">
<group
id="tab_group_general" string="General"
colspan="2" col="2"
>
<field name="code" />
<field name="name" />
</group>
<group
id="tab_group_target"
string="Select partner type and category for tab"
colspan="2" col="2"
>
<field name="contact_type" />
<field name="partner_category_id" />
</group>
<separator
colspan="2"
string="Select specific partners to have this tab"
/>
<field name="partner_ids" colspan="2" nolabel="1"/>
</group>
</form>
</field>
</record>
</odoo>

1
setup/_metapackage/setup.py

@ -44,6 +44,7 @@ setuptools.setup(
'odoo12-addon-partner_identification_gln',
'odoo12-addon-partner_industry_secondary',
'odoo12-addon-partner_multi_relation',
'odoo12-addon-partner_multi_relation_tabs',
'odoo12-addon-partner_phone_extension',
'odoo12-addon-partner_phonecall_schedule',
'odoo12-addon-partner_postal_address',

Loading…
Cancel
Save