Ronald Portier
6 years ago
committed by
Holger Brunn
19 changed files with 1180 additions and 0 deletions
-
63partner_multi_relation_tabs/README.rst
-
4partner_multi_relation_tabs/__init__.py
-
25partner_multi_relation_tabs/__manifest__.py
-
182partner_multi_relation_tabs/i18n/nl.po
-
181partner_multi_relation_tabs/i18n/partner_multi_relation_tabs.pot
-
8partner_multi_relation_tabs/models/__init__.py
-
158partner_multi_relation_tabs/models/res_partner.py
-
55partner_multi_relation_tabs/models/res_partner_relation_all.py
-
58partner_multi_relation_tabs/models/res_partner_relation_type.py
-
36partner_multi_relation_tabs/models/res_partner_relation_type_selection.py
-
102partner_multi_relation_tabs/models/res_partner_tab.py
-
3partner_multi_relation_tabs/security/ir.model.access.csv
-
BINpartner_multi_relation_tabs/static/description/icon.png
-
4partner_multi_relation_tabs/tests/__init__.py
-
217partner_multi_relation_tabs/tests/test_partner_tabs.py
-
18partner_multi_relation_tabs/views/menu.xml
-
17partner_multi_relation_tabs/views/res_partner_relation_all.xml
-
20partner_multi_relation_tabs/views/res_partner_relation_type.xml
-
29partner_multi_relation_tabs/views/res_partner_tab.xml
@ -0,0 +1,63 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/agpl |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
======================== |
||||
|
Partner Relations in tab |
||||
|
======================== |
||||
|
|
||||
|
This module adds the possibility to show certain partner relations in its own |
||||
|
tab instead of the list of all relations. This can be useful if certain |
||||
|
relation types are regularly used and should be overseeable at a glace. |
||||
|
|
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
To use this module, you need to: |
||||
|
|
||||
|
#. Go to ... |
||||
|
|
||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
||||
|
:alt: Try me on Runbot |
||||
|
:target: https://runbot.odoo-community.org/runbot/partner-contact/10.0 |
||||
|
|
||||
|
|
||||
|
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 smash it by providing detailed and welcomed feedback. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
|
||||
|
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> |
||||
|
|
||||
|
Do not contact contributors directly about support or help with technical issues. |
||||
|
|
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2014-2017 Therp BV <https://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from . import models |
@ -0,0 +1,25 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# 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": "10.0.1.0.0", |
||||
|
"author": "Therp BV,Odoo Community Association (OCA)", |
||||
|
"license": "AGPL-3", |
||||
|
"complexity": "normal", |
||||
|
"category": "Customer Relationship Management", |
||||
|
"depends": [ |
||||
|
'web_tree_many2one_clickable', |
||||
|
'partner_multi_relation', |
||||
|
], |
||||
|
"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, |
||||
|
} |
@ -0,0 +1,182 @@ |
|||||
|
# 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" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: nl\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: partner_multi_relation_tabs |
||||
|
#: code:addons/partner_multi_relation_tabs/models/res_partner.py:26 |
||||
|
#, python-format |
||||
|
msgid "Adding field %s to res.partner nodel." |
||||
|
msgstr "Veld %s wordt toegevoegd aan res.partner model." |
||||
|
|
||||
|
#. 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 |
||||
|
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:32 |
||||
|
#, 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:52 |
||||
|
#, 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: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: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:ir.model,name:partner_multi_relation_tabs.model_res_partner |
||||
|
msgid "Partner" |
||||
|
msgstr "Relatie" |
||||
|
|
||||
|
#. 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.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:37 |
||||
|
#, 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:57 |
||||
|
#, 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_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 |
||||
|
#: code:addons/partner_multi_relation_tabs/models/res_partner.py:39 |
||||
|
#, python-format |
||||
|
msgid "Updating field %s in res.partner nodel." |
||||
|
msgstr "Veld %s op res.partner model wordt bijgewerkt." |
||||
|
|
||||
|
#. 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.py:45 |
||||
|
#, python-format |
||||
|
msgid "deleting field %s from res.partner nodel." |
||||
|
msgstr "verwijderen veld % van res.partner model." |
||||
|
|
@ -0,0 +1,181 @@ |
|||||
|
# 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: <>\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 |
||||
|
#: code:addons/partner_multi_relation_tabs/models/res_partner.py:26 |
||||
|
#, python-format |
||||
|
msgid "Adding field %s to res.partner nodel." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. 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 |
||||
|
#: code:addons/partner_multi_relation_tabs/models/res_partner_relation_type.py:32 |
||||
|
#, 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:52 |
||||
|
#, 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: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: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:ir.model,name:partner_multi_relation_tabs.model_res_partner |
||||
|
msgid "Partner" |
||||
|
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.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:37 |
||||
|
#, 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:57 |
||||
|
#, 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_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 |
||||
|
#: code:addons/partner_multi_relation_tabs/models/res_partner.py:39 |
||||
|
#, python-format |
||||
|
msgid "Updating field %s in res.partner nodel." |
||||
|
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.py:45 |
||||
|
#, python-format |
||||
|
msgid "deleting field %s from res.partner nodel." |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,8 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2014-2017 Therp BV <https://therp.nl> |
||||
|
# 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 |
@ -0,0 +1,158 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2014-2018 Therp BV <https://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
import logging |
||||
|
from lxml import etree |
||||
|
|
||||
|
from odoo.osv.orm import transfer_modifiers_to_node |
||||
|
from odoo.osv import expression |
||||
|
from odoo import _, api, fields, models |
||||
|
|
||||
|
|
||||
|
_logger = logging.getLogger(__name__) |
||||
|
NAME_PREFIX = 'relation_ids_tab' |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
_inherit = 'res.partner' |
||||
|
|
||||
|
def _get_tab_fieldname(self, tab): |
||||
|
"""Create fieldname for tab.""" |
||||
|
return '%s_%s' % (NAME_PREFIX, tab.id) |
||||
|
|
||||
|
@api.model |
||||
|
def _add_tab_field(self, tab): |
||||
|
fieldname = self._get_tab_fieldname(tab) |
||||
|
_logger.info(_( |
||||
|
"Adding field %s to res.partner model." % fieldname)) |
||||
|
field = fields.One2many( |
||||
|
comodel_name='res.partner.relation.all', |
||||
|
inverse_name='this_partner_id', |
||||
|
domain=[('tab_id', '=', tab.id)], |
||||
|
string=tab.name) |
||||
|
self._add_field(fieldname, field) |
||||
|
|
||||
|
@api.model |
||||
|
def _update_tab_field(self, tab): |
||||
|
fieldname = self._get_tab_fieldname(tab) |
||||
|
if fieldname not in self._fields: |
||||
|
return self._add_tab_field(tab) |
||||
|
_logger.info(_( |
||||
|
"Updating field %s in res.partner model." % fieldname)) |
||||
|
self._fields[fieldname].string = tab.name |
||||
|
|
||||
|
@api.model |
||||
|
def _delete_tab_field(self, fieldname): |
||||
|
_logger.info(_( |
||||
|
"deleting field %s from res.partner model." % fieldname)) |
||||
|
self._pop_field(fieldname) |
||||
|
|
||||
|
@api.model |
||||
|
def _update_tab_fields(self): |
||||
|
"""Create a field for each tab that might be shown for a partner.""" |
||||
|
deprecated_tab_fields = [ |
||||
|
name for name in self._fields |
||||
|
if name.startswith(NAME_PREFIX)] |
||||
|
tab_model = self.env['res.partner.tab'] |
||||
|
for tab in tab_model.search([]): # get all tabs |
||||
|
fieldname = self._get_tab_fieldname(tab) |
||||
|
self._add_tab_field(tab) |
||||
|
if fieldname in deprecated_tab_fields: |
||||
|
deprecated_tab_fields.remove(fieldname) # not deprecated |
||||
|
for fieldname in deprecated_tab_fields: |
||||
|
self._delete_tab_field(fieldname) |
||||
|
|
||||
|
def _register_hook(self): |
||||
|
self._update_tab_fields() |
||||
|
|
||||
|
def _create_tab_page(self, fieldname, tab): |
||||
|
"""Create an xml node containing the tab page to be added view.""" |
||||
|
# pylint: disable=no-member |
||||
|
tab_page = etree.Element('page') |
||||
|
invisible = [('id', '=', False)] # Partner not created yet |
||||
|
if tab.partner_ids: |
||||
|
invisible = expression.OR([ |
||||
|
invisible, |
||||
|
[('id', 'not in', tab.partner_ids.ids)]]) |
||||
|
else: |
||||
|
if tab.contact_type: |
||||
|
invisible = expression.OR([ |
||||
|
invisible, |
||||
|
[('is_company', '=', tab.contact_type != 'c')]]) |
||||
|
if tab.partner_category_id: |
||||
|
invisible = expression.OR([ |
||||
|
invisible, |
||||
|
[('category_id', '!=', tab.partner_category_id.id)]]) |
||||
|
attrs = {'invisible': invisible} |
||||
|
tab_page.set('string', tab.name) |
||||
|
tab_page.set('attrs', repr(attrs)) |
||||
|
transfer_modifiers_to_node(attrs, tab_page) |
||||
|
field = etree.Element( |
||||
|
'field', |
||||
|
name=fieldname, |
||||
|
context='{' |
||||
|
'"default_this_partner_id": id,' |
||||
|
'"default_tab_id": %d,' |
||||
|
'"active_test": False}' % tab.id) |
||||
|
tree = etree.Element('tree', editable='bottom') |
||||
|
# 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', '=', tab.id)])) |
||||
|
type_field.set('options', repr({'no_create': True})) |
||||
|
tree.append(type_field) |
||||
|
other_partner_field = etree.Element( |
||||
|
'field', |
||||
|
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')) |
||||
|
field.append(tree) |
||||
|
tab_page.append(field) |
||||
|
return tab_page |
||||
|
|
||||
|
def _add_tab_pages(self, view): |
||||
|
"""Adds the relevant tabs to the partner's formview.""" |
||||
|
# pylint: disable=no-member |
||||
|
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"]'): |
||||
|
view.append( |
||||
|
etree.Element('field', name='id', invisible='True')) |
||||
|
extra_fields.append('id') |
||||
|
last_page = last_page_nodes[0] |
||||
|
tab_model = self.env['res.partner.tab'] |
||||
|
for tab in tab_model.search([]): # get all tabs |
||||
|
fieldname = self._get_tab_fieldname(tab) |
||||
|
self._update_tab_field(tab) |
||||
|
extra_fields.append(fieldname) |
||||
|
tab_page = self._create_tab_page(fieldname, tab) |
||||
|
last_page.addnext(tab_page) |
||||
|
last_page = tab_page # Keep ordering of tabs |
||||
|
return extra_fields |
||||
|
|
||||
|
@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']) # pylint: disable=no-member |
||||
|
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 |
@ -0,0 +1,55 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2014-2017 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp 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.""" |
||||
|
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.""" |
||||
|
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 then when a relation is added to a tab, |
||||
|
it is with a relation type meant to be placed on that tab. |
||||
|
""" |
||||
|
result = super(ResPartnerRelationAll, self).onchange_partner_id() |
||||
|
if 'default_tab_id' in self.env.context: |
||||
|
if 'domain' not in result: |
||||
|
result['domain'] = {} |
||||
|
if 'type_selection_id' not in result['domain']: |
||||
|
result['domain']['type_selection_id'] = [] |
||||
|
selection_domain = result['domain']['type_selection_id'] |
||||
|
selection_domain.append( |
||||
|
('tab_id', '=', self.env.context['default_tab_id'])) |
||||
|
return result |
@ -0,0 +1,58 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2014-2017 Therp BV <https://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from odoo import _, api, fields, models |
||||
|
from odoo.exceptions import ValidationError |
||||
|
|
||||
|
|
||||
|
class ResPartnerRelationType(models.Model): |
||||
|
_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")) |
@ -0,0 +1,36 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2013-2017 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp 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"]) |
@ -0,0 +1,102 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2017-2018 Therp BV <https://therp.nl>. |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from odoo import _, api, fields, models |
||||
|
from odoo.exceptions import ValidationError |
||||
|
|
||||
|
|
||||
|
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.model |
||||
|
def create(self, vals): |
||||
|
new_tab = super(ResPartnerTab, self).create(vals) |
||||
|
partner_model = self.env['res.partner'] |
||||
|
partner_model._add_tab_field(new_tab) |
||||
|
return new_tab |
||||
|
|
||||
|
@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) |
||||
|
partner_model = self.env['res.partner'] |
||||
|
for this in self: |
||||
|
partner_model._update_tab_field(this) |
||||
|
return result |
||||
|
|
||||
|
@api.multi |
||||
|
def unlink(self): |
||||
|
"""Unlink should first remove references.""" |
||||
|
self.update_types() |
||||
|
partner_model = self.env['res.partner'] |
||||
|
for this in self: |
||||
|
fieldname = partner_model._get_tab_fieldname(this) |
||||
|
partner_model._delete_tab_field(fieldname) |
||||
|
return super(ResPartnerTab, self).unlink() |
@ -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 |
After Width: 90 | Height: 90 | Size: 18 KiB |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2014-2017 Therp BV <https://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from . import test_partner_tabs |
@ -0,0 +1,217 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2014-2017 Therp BV <https://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from lxml import etree |
||||
|
|
||||
|
from odoo.exceptions import ValidationError |
||||
|
from odoo.tests import common |
||||
|
|
||||
|
|
||||
|
class FakeTab(): |
||||
|
|
||||
|
def __init__(self, id, name): |
||||
|
self.id = id |
||||
|
self.name = name |
||||
|
|
||||
|
|
||||
|
class TestPartnerTabs(common.SingleTransactionCase): |
||||
|
|
||||
|
post_install = True |
||||
|
|
||||
|
def test_create_tab(self): |
||||
|
tab_model = self.env['res.partner.tab'] |
||||
|
partner_model = self.env['res.partner'] |
||||
|
new_tab = tab_model.create({ |
||||
|
'code': 'executive', |
||||
|
'name': 'Executive members', |
||||
|
'contact_type': 'c'}) |
||||
|
self.assertTrue(bool(new_tab)) |
||||
|
# There should now be a field in res_partner for the new tab. |
||||
|
fieldname = partner_model._get_tab_fieldname(new_tab) |
||||
|
self.assertTrue(fieldname in partner_model._fields) |
||||
|
# The form view for partner should now also contain the tab, |
||||
|
# if the view contains tabs in the first place. |
||||
|
view_partner_form = self.env.ref('base.view_partner_form') |
||||
|
view = partner_model.with_context().fields_view_get( |
||||
|
view_id=view_partner_form.id, view_type='form') |
||||
|
tree = etree.fromstring(view['arch']) |
||||
|
field = tree.xpath('//field[@name="id"]') |
||||
|
self.assertTrue(field, 'Id field does not exist.') |
||||
|
# 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 = 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_tab_modifications(self): |
||||
|
category_model = self.env['res.partner.category'] |
||||
|
tab_model = self.env['res.partner.tab'] |
||||
|
type_model = self.env['res.partner.relation.type'] |
||||
|
category_government = category_model.create({'name': 'Government'}) |
||||
|
executive_tab = tab_model.create({ |
||||
|
'code': 'executive', |
||||
|
'name': 'Executive members'}) |
||||
|
self.assertTrue(bool(executive_tab)) |
||||
|
type_has_chairperson = type_model.create({ |
||||
|
'name': 'has chairperson', |
||||
|
'name_inverse': 'is chairperson for', |
||||
|
'contact_type_right': 'p', |
||||
|
'tab_left_id': executive_tab.id}) |
||||
|
self.assertTrue(bool(type_has_chairperson)) |
||||
|
# If we change tab now to be only valid on company partners |
||||
|
# the tab_left_id field should be cleared from the type: |
||||
|
executive_tab.write({ |
||||
|
'contact_type': 'c', |
||||
|
'partner_category_id': category_government.id}) |
||||
|
self.assertFalse(type_has_chairperson.tab_left_id.id) |
||||
|
# Trying to set the tab back on type should be impossible: |
||||
|
with self.assertRaises(ValidationError): |
||||
|
type_has_chairperson.write({'tab_left_id': executive_tab.id}) |
||||
|
# We should be able to change tab, if also changing contact type |
||||
|
# and category: |
||||
|
type_has_chairperson.write({ |
||||
|
'partner_category_left': category_government.id, |
||||
|
'contact_type_left': 'c', |
||||
|
'tab_left_id': executive_tab.id}) |
||||
|
self.assertEqual( |
||||
|
type_has_chairperson.tab_left_id.id, |
||||
|
executive_tab.id) |
||||
|
# Unlinking the tab should reset the tab name on relations: |
||||
|
executive_tab.unlink() |
||||
|
self.assertEqual( |
||||
|
type_has_chairperson.tab_left_id.id, |
||||
|
False) |
||||
|
|
||||
|
def test_relation_type_modifications(self): |
||||
|
category_model = self.env['res.partner.category'] |
||||
|
tab_model = self.env['res.partner.tab'] |
||||
|
type_model = self.env['res.partner.relation.type'] |
||||
|
category_government = category_model.create({'name': 'Government'}) |
||||
|
category_positions = category_model.create({'name': 'Positions'}) |
||||
|
executive_tab = tab_model.create({ |
||||
|
'code': 'executive', |
||||
|
'name': 'Executive members', |
||||
|
'contact_type': 'c', |
||||
|
'partner_category_id': category_government.id}) |
||||
|
self.assertTrue(bool(executive_tab)) |
||||
|
positions_tab = tab_model.create({ |
||||
|
'code': 'positions', |
||||
|
'name': 'Positions held', |
||||
|
'contact_type': 'p', |
||||
|
'partner_category_id': category_positions.id}) |
||||
|
self.assertTrue(bool(executive_tab)) |
||||
|
type_has_chairperson = type_model.create({ |
||||
|
'name': 'has chairperson', |
||||
|
'name_inverse': 'is chairperson for', |
||||
|
'partner_category_left': category_government.id, |
||||
|
'contact_type_left': 'c', |
||||
|
'tab_left_id': executive_tab.id, |
||||
|
'partner_category_right': category_positions.id, |
||||
|
'contact_type_right': 'p', |
||||
|
'tab_right_id': positions_tab.id}) |
||||
|
self.assertTrue(bool(type_has_chairperson)) |
||||
|
# Trying to clear either category should raise ValidationError: |
||||
|
with self.assertRaises(ValidationError): |
||||
|
type_has_chairperson.write({'partner_category_left': False}) |
||||
|
with self.assertRaises(ValidationError): |
||||
|
type_has_chairperson.write({'partner_category_right': False}) |
||||
|
# Trying to clear either contact type should raise ValidationError: |
||||
|
with self.assertRaises(ValidationError): |
||||
|
type_has_chairperson.write({'contact_type_left': False}) |
||||
|
with self.assertRaises(ValidationError): |
||||
|
type_has_chairperson.write({'contact_type_right': False}) |
||||
|
|
||||
|
def test_relations(self): |
||||
|
"""Test relations shown on tab.""" |
||||
|
tab_model = self.env['res.partner.tab'] |
||||
|
type_model = self.env['res.partner.relation.type'] |
||||
|
partner_model = self.env['res.partner'] |
||||
|
relation_model = self.env['res.partner.relation'] |
||||
|
relation_all_model = self.env['res.partner.relation.all'] |
||||
|
executive_tab = tab_model.create({ |
||||
|
'code': 'executive', |
||||
|
'name': 'Executive members'}) |
||||
|
self.assertTrue(bool(executive_tab)) |
||||
|
type_has_chairperson = type_model.create({ |
||||
|
'name': 'has chairperson', |
||||
|
'name_inverse': 'is chairperson for', |
||||
|
'contact_type_right': 'p', |
||||
|
'tab_left_id': executive_tab.id}) |
||||
|
self.assertTrue(bool(type_has_chairperson)) |
||||
|
big_company = partner_model.create({ |
||||
|
'name': 'Big company', |
||||
|
'is_company': True, |
||||
|
'ref': 'BIG'}) |
||||
|
self.assertTrue(bool(big_company)) |
||||
|
important_person = partner_model.create({ |
||||
|
'name': 'Bart Simpson', |
||||
|
'is_company': False, |
||||
|
'ref': 'BS'}) |
||||
|
self.assertTrue(bool(important_person)) |
||||
|
relation_company_chair = relation_model.create({ |
||||
|
'left_partner_id': big_company.id, |
||||
|
'type_id': type_has_chairperson.id, |
||||
|
'right_partner_id': important_person.id}) |
||||
|
self.assertTrue(bool(relation_company_chair)) |
||||
|
# Now we should be able to find the relation with the tab_id: |
||||
|
relation_all_company_chair = relation_all_model.search([ |
||||
|
('tab_id', '=', executive_tab.id)], limit=1) |
||||
|
self.assertTrue(bool(relation_all_company_chair)) |
||||
|
self.assertEqual( |
||||
|
relation_company_chair.left_partner_id.id, |
||||
|
relation_all_company_chair.this_partner_id.id) |
||||
|
# We should find the company on the partner through tab field: |
||||
|
fieldname = partner_model._get_tab_fieldname(executive_tab) |
||||
|
self.assertTrue(fieldname in partner_model._fields) |
||||
|
executive_partners = big_company[fieldname] |
||||
|
self.assertEqual(len(executive_partners), 1) |
||||
|
self.assertEqual( |
||||
|
executive_partners.other_partner_id.id, |
||||
|
important_person.id) |
||||
|
# When adding a new relation on a tab, type must be for tab. |
||||
|
onchange_result = executive_partners.with_context( |
||||
|
default_tab_id=executive_tab.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', '=', executive_tab.id)) |
||||
|
|
||||
|
def test_update_tabs(self): |
||||
|
"""Test the function that will create tabs during module loading.""" |
||||
|
tab_model = self.env['res.partner.tab'] |
||||
|
partner_model = self.env['res.partner'] |
||||
|
executive_tab = tab_model.create({ |
||||
|
'code': 'executive', |
||||
|
'name': 'Executive members'}) |
||||
|
self.assertTrue(bool(executive_tab)) |
||||
|
tabfield_executive_name = partner_model._get_tab_fieldname( |
||||
|
executive_tab) |
||||
|
# Create some fake tab fields (should be removed). |
||||
|
tab_123 = FakeTab(123, 'First tab') |
||||
|
tab_456 = FakeTab(456, 'Second tab') |
||||
|
# Add "tab fields" |
||||
|
partner_model._add_tab_field(tab_123) |
||||
|
tabfield_123_name = partner_model._get_tab_fieldname(tab_123) |
||||
|
self.assertEqual( |
||||
|
partner_model._fields[tabfield_123_name].string, tab_123.name) |
||||
|
partner_model._add_tab_field(tab_456) |
||||
|
tabfield_456_name = partner_model._get_tab_fieldname(tab_456) |
||||
|
self.assertEqual( |
||||
|
partner_model._fields[tabfield_456_name].string, tab_456.name) |
||||
|
# Now call hook method |
||||
|
partner_model._register_hook() |
||||
|
self.assertFalse(tabfield_123_name in partner_model._fields) |
||||
|
self.assertFalse(tabfield_456_name in partner_model._fields) |
||||
|
self.assertTrue(tabfield_executive_name in partner_model._fields) |
@ -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="sales_team.menu_config_address_book" |
||||
|
action="action_res_partner_tab" |
||||
|
sequence="80" |
||||
|
/> |
||||
|
|
||||
|
</odoo> |
@ -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> |
@ -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> |
@ -0,0 +1,29 @@ |
|||||
|
<?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> |
||||
|
<field name="code" /> |
||||
|
<field name="name" /> |
||||
|
<field name="contact_type" /> |
||||
|
<field name="partner_category_id" /> |
||||
|
<field name="partner_ids" /> |
||||
|
</group> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue