No known key found for this signature in database
GPG Key ID: 5B4EF742F8CD859C
25 changed files with 518 additions and 25 deletions
-
2partner_multi_relation/__init__.py
-
2partner_multi_relation/__manifest__.py
-
2partner_multi_relation/models/__init__.py
-
2partner_multi_relation/models/res_partner.py
-
2partner_multi_relation/models/res_partner_relation.py
-
2partner_multi_relation/models/res_partner_relation_all.py
-
45partner_multi_relation/models/res_partner_relation_type.py
-
2partner_multi_relation/models/res_partner_relation_type_selection.py
-
2partner_multi_relation/tests/__init__.py
-
6partner_multi_relation/tests/test_partner_relation.py
-
2partner_multi_relation/tests/test_partner_relation_all.py
-
2partner_multi_relation/tests/test_partner_relation_common.py
-
2partner_multi_relation/tests/test_partner_search.py
-
63partner_multi_relation_tabs/README.rst
-
4partner_multi_relation_tabs/__init__.py
-
20partner_multi_relation_tabs/__manifest__.py
-
36partner_multi_relation_tabs/i18n/nl.po
-
43partner_multi_relation_tabs/i18n/partner_relations_in_tab.pot
-
5partner_multi_relation_tabs/models/__init__.py
-
122partner_multi_relation_tabs/models/res_partner.py
-
59partner_multi_relation_tabs/models/res_partner_relation_type.py
-
BINpartner_multi_relation_tabs/static/description/icon.png
-
4partner_multi_relation_tabs/tests/__init__.py
-
94partner_multi_relation_tabs/tests/test_relations.py
-
20partner_multi_relation_tabs/views/res_partner_relation_type.xml
@ -1,5 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2013-2016 Therp BV <http://therp.nl> |
|||
# © 2013-2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from . import models |
|||
from . import tests |
@ -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 -*- |
|||
# © 2014-2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from . import models |
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2014-2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://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": [ |
|||
'partner_multi_relation', |
|||
], |
|||
"data": [ |
|||
"views/res_partner_relation_type.xml", |
|||
], |
|||
"auto_install": False, |
|||
"installable": True, |
|||
"application": False, |
|||
} |
@ -0,0 +1,36 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * partner_relations_in_tab |
|||
# |
|||
# Translators: |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: partner-contact (10.0)\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2015-10-01 13:16+0000\n" |
|||
"PO-Revision-Date: 2015-05-22 13:07+0000\n" |
|||
"Last-Translator: Maxime Chambreuil <maxime.chambreuil@gmail.com>\n" |
|||
"Language-Team: Dutch (http://www.transifex.com/oca/OCA-partner-contact-7-0/language/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_relations_in_tab |
|||
#: code:addons/partner_relations_in_tab/model/res_partner.py:99 |
|||
#: model:ir.model,name:partner_relations_in_tab.model_res_partner |
|||
#, python-format |
|||
msgid "Partner" |
|||
msgstr "Relatie" |
|||
|
|||
#. module: partner_relations_in_tab |
|||
#: field:res.partner.relation.type,own_tab_left:0 |
|||
#: field:res.partner.relation.type,own_tab_right:0 |
|||
msgid "Show in own tab" |
|||
msgstr "Toon in eigen tabblad" |
|||
|
|||
#. module: partner_relations_in_tab |
|||
#: model:ir.model,name:partner_relations_in_tab.model_res_partner_relation_type |
|||
msgid "Parter relation type" |
|||
msgstr "Type relatiekoppeling" |
@ -0,0 +1,43 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * partner_relations_in_tab |
|||
# |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: OpenERP Server 10.0\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2014-11-25 09:08+0000\n" |
|||
"PO-Revision-Date: 2014-11-25 09:08+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_relations_in_tab |
|||
#: field:res.partner,id:0 |
|||
msgid "Id" |
|||
msgstr "" |
|||
|
|||
#. module: partner_relations_in_tab |
|||
#: code:_description:0 |
|||
#: model:ir.model,name:partner_relations_in_tab.model_res_partner_relation_type |
|||
#, python-format |
|||
msgid "Parter relation type" |
|||
msgstr "" |
|||
|
|||
#. module: partner_relations_in_tab |
|||
#: code:_description:0 |
|||
#: code:addons/partner_relations_in_tab/model/res_partner.py:99 |
|||
#: model:ir.model,name:partner_relations_in_tab.model_res_partner |
|||
#, python-format |
|||
msgid "Partner" |
|||
msgstr "" |
|||
|
|||
#. module: partner_relations_in_tab |
|||
#: field:res.partner.relation.type,own_tab_left:0 |
|||
#: field:res.partner.relation.type,own_tab_right:0 |
|||
msgid "Show in own tab" |
|||
msgstr "" |
|||
|
@ -0,0 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2014-2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from . import res_partner_relation_type |
|||
from . import res_partner |
@ -0,0 +1,122 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2014-2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from lxml import etree |
|||
from odoo.osv.orm import Model, transfer_modifiers_to_node |
|||
from odoo.osv import expression |
|||
from odoo import api, _ |
|||
|
|||
TAB_LEFT = 'left' |
|||
TAB_RIGHT = 'right' |
|||
|
|||
|
|||
class ResPartner(Model): |
|||
_inherit = 'res.partner' |
|||
|
|||
def _create_relation_type_tab(self, rel_type, current_tab_postfix, |
|||
field_names): |
|||
"""Create an xml node containing the relation's tab to be added to the |
|||
view. Add the field(s) created on the form to field_names.""" |
|||
name = rel_type.name if current_tab_postfix == TAB_LEFT \ |
|||
else rel_type.name_inverse |
|||
contact_type = rel_type['contact_type_' + current_tab_postfix] |
|||
partner_category = rel_type['partner_category_' + current_tab_postfix] |
|||
tab = etree.Element('page') |
|||
tab.set('string', name) |
|||
invisible = [('id', '=', False)] |
|||
if contact_type: |
|||
invisible = expression.OR([ |
|||
invisible, |
|||
[('is_company', '=', contact_type != 'c')]]) |
|||
if partner_category: |
|||
invisible = expression.OR([ |
|||
invisible, |
|||
[('category_id', '!=', partner_category.id)]]) |
|||
attrs = { |
|||
'invisible': invisible, |
|||
} |
|||
tab.set('attrs', repr(attrs)) |
|||
transfer_modifiers_to_node(attrs, tab) |
|||
field_name = 'relation_ids_own_tab_%s_%s' % ( |
|||
rel_type.id, current_tab_postfix) |
|||
field_names.append(field_name) |
|||
this_partner_name = '%s_partner_id' % (current_tab_postfix) |
|||
other_partner_name = '%s_partner_id' % ( |
|||
TAB_RIGHT if current_tab_postfix == TAB_LEFT else TAB_LEFT) |
|||
field = etree.Element( |
|||
'field', |
|||
name=field_name, |
|||
context=('{"default_type_id": %s, "default_%s": id, ' |
|||
'"active_test": False}') % ( |
|||
rel_type.id, |
|||
this_partner_name)) |
|||
tab.append(field) |
|||
tree = etree.Element('tree', editable='bottom') |
|||
field.append(tree) |
|||
partner_type = rel_type.contact_type_left \ |
|||
if current_tab_postfix == TAB_LEFT else rel_type.contact_type_right |
|||
if partner_type == 'c': |
|||
is_company = True |
|||
else: |
|||
is_company = False |
|||
tree.append(etree.Element( |
|||
'field', |
|||
string=_('Partner'), |
|||
domain=repr([('is_company', '=', is_company)]), |
|||
name=other_partner_name)) |
|||
tree.append(etree.Element( |
|||
'field', |
|||
name='date_start')) |
|||
tree.append(etree.Element( |
|||
'field', |
|||
name='date_end')) |
|||
tree.append(etree.Element('field', name='type_id', |
|||
invisible='True')) |
|||
tree.append(etree.Element('field', name=this_partner_name, |
|||
invisible='True')) |
|||
return tab |
|||
|
|||
def _add_relation_type_tab(self, rel_type, field_names, |
|||
element_last_page_hook): |
|||
""" |
|||
Adds the relevant tabs to the partner's formview. |
|||
""" |
|||
if rel_type.own_tab_left: |
|||
tab = self._create_relation_type_tab( |
|||
rel_type, TAB_LEFT, field_names) |
|||
element_last_page_hook.addnext(tab) |
|||
if rel_type.own_tab_right and not rel_type.is_symmetric: |
|||
tab = self._create_relation_type_tab( |
|||
rel_type, TAB_RIGHT, field_names) |
|||
element_last_page_hook.addnext(tab) |
|||
|
|||
@api.model |
|||
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, |
|||
submenu=False): |
|||
result = super(ResPartner, self).fields_view_get( |
|||
view_id=view_id, view_type=view_type, |
|||
toolbar=toolbar, submenu=submenu) |
|||
if view_type == 'form' and not self.env.context.get('check_view_ids'): |
|||
res_partner_relation_type = self.env['res.partner.relation.type'] |
|||
own_tab_types = res_partner_relation_type.search( |
|||
['|', |
|||
('own_tab_left', '=', True), |
|||
('own_tab_right', '=', True) |
|||
]) |
|||
view = etree.fromstring(result['arch']) |
|||
element_last_page_hook = view.xpath('//page[last()]') |
|||
element_last_page_hook = element_last_page_hook[0] |
|||
field_names = [] |
|||
if not view.xpath('//field[@name="id"]'): |
|||
view.append(etree.Element('field', name='id', |
|||
invisible='True')) |
|||
field_names.append('id') |
|||
for rel_type in own_tab_types: |
|||
self._add_relation_type_tab( |
|||
rel_type, field_names, element_last_page_hook) |
|||
ir_ui_view_obj = self.env['ir.ui.view'] |
|||
result['arch'], fields = ir_ui_view_obj.postprocess_and_fields( |
|||
self._name, view, result['view_id']) |
|||
for field_name in field_names: |
|||
result['fields'][field_name] = fields[field_name] |
|||
return result |
@ -0,0 +1,59 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2014-2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from odoo import api, fields, models |
|||
TAB_LEFT = 'left' |
|||
TAB_RIGHT = 'right' |
|||
|
|||
|
|||
class ResPartnerRelationType(models.Model): |
|||
_inherit = 'res.partner.relation.type' |
|||
|
|||
own_tab_left = fields.Boolean('Show in own tab', default=False) |
|||
own_tab_right = fields.Boolean('Show in own tab', default=False) |
|||
|
|||
def _update_res_partner_fields(self): |
|||
field_name_prefix = 'relation_ids_own_tab_' |
|||
field_name_format = field_name_prefix + '%s_%s' |
|||
res_partner = self.env['res.partner'] |
|||
for field_name in res_partner._fields.copy(): |
|||
if field_name.startswith(field_name_prefix): |
|||
del res_partner._fields[field_name] |
|||
|
|||
def add_field(relation, _tab): |
|||
field = fields.One2many( |
|||
'res.partner.relation', |
|||
'%s_partner_id' % (_tab), |
|||
domain=[('type_id.id', '=', relation.id)], |
|||
string=relation['name' if _tab == TAB_LEFT |
|||
else 'name_inverse'], |
|||
) |
|||
field_name = field_name_format % (relation.id, _tab) |
|||
res_partner._add_field(field_name, field) |
|||
for relation in self.sudo().search( |
|||
['|', |
|||
('own_tab_left', '=', True), |
|||
('own_tab_right', '=', True), |
|||
]): |
|||
if relation.own_tab_left: |
|||
add_field(relation, TAB_LEFT) |
|||
if relation.own_tab_right: |
|||
add_field(relation, TAB_RIGHT) |
|||
|
|||
def _register_hook(self): |
|||
self._update_res_partner_fields() |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
result = super(ResPartnerRelationType, self).create(vals) |
|||
if vals.get('own_tab_left') or vals.get('own_tab_right'): |
|||
self._update_res_partner_fields() |
|||
return result |
|||
|
|||
@api.multi |
|||
def write(self, vals): |
|||
result = super(ResPartnerRelationType, self).write(vals) |
|||
for record in self: |
|||
if 'own_tab_left' in vals or 'own_tab_right' in vals: |
|||
record._update_res_partner_fields() |
|||
return result |
After Width: 90 | Height: 90 | Size: 18 KiB |
@ -0,0 +1,4 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from . import test_relations |
@ -0,0 +1,94 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from odoo.tests import common |
|||
from lxml import etree |
|||
|
|||
|
|||
class TestRelations(common.SingleTransactionCase): |
|||
|
|||
post_install = True |
|||
|
|||
def test_person_to_person_relation(self): |
|||
res_partner_relation_type_model = self.env['res.partner.relation.type'] |
|||
res_partner_relation_type_selection_model = self.env[ |
|||
'res.partner.relation.type.selection'] |
|||
p2p_rel = res_partner_relation_type_model.create({ |
|||
'name': 'Employer', |
|||
'contact_type_left': 'p', |
|||
'name_inverse': 'Employee', |
|||
'contact_type_right': 'p' |
|||
}) |
|||
p2p_rel.write({'own_tab_left': True}) |
|||
p2p_rel_typ = res_partner_relation_type_selection_model.search( |
|||
[('type_id', '=', p2p_rel.id)], limit=1).id |
|||
res_partner_model = self.env['res.partner'] |
|||
employer = res_partner_model.create({'name': 'Employer'}) |
|||
employee = res_partner_model.create({'name': 'Employee'}) |
|||
res_partner_relation_all_model = self.env['res.partner.relation.all'] |
|||
res_partner_relation_all_model.create({ |
|||
'this_partner_id': employer.id, |
|||
'other_partner_id': employee.id, |
|||
'type_selection_id': p2p_rel_typ |
|||
}) |
|||
result = employer.with_context().fields_view_get() |
|||
# we check whether the company's res.partner form contains the |
|||
# appropriate views (inserted by fields_view_get |
|||
tree = etree.fromstring(result['arch']) |
|||
field = tree.xpath('field[@name="id"]') |
|||
self.assertTrue(field, 'Id field does not exist.') |
|||
# initially we should have the left and not the right |
|||
self.assertTrue('relation_ids_own_tab_{}_left'.format( |
|||
p2p_rel.id in employee._fields)) |
|||
self.assertTrue('relation_ids_own_tab_{}_right'.format( |
|||
p2p_rel.id not in employee._fields)) |
|||
p2p_rel.write({'is_symmetric': True}) |
|||
# now we should have them both |
|||
self.assertTrue('relation_ids_own_tab_{}_left'.format( |
|||
p2p_rel.id in employee._fields)) |
|||
self.assertTrue('relation_ids_own_tab_{}_right'.format( |
|||
p2p_rel.id in employee._fields)) |
|||
|
|||
def test_person_to_company_relation(self): |
|||
res_partner_relation_type_model = self.env['res.partner.relation.type'] |
|||
res_partner_relation_type_selection_model = self.env[ |
|||
'res.partner.relation.type.selection'] |
|||
res_partner_relation_all_model = self.env['res.partner.relation.all'] |
|||
res_partner_model = self.env['res.partner'] |
|||
company = res_partner_model.create({ |
|||
'name': 'Company', |
|||
'is_company': True |
|||
}) |
|||
employer = res_partner_model.create({'name': 'Employer'}) |
|||
c2p_rel = res_partner_relation_type_model.create({ |
|||
'name': 'Company', |
|||
'contact_type_left': 'c', |
|||
'name_inverse': 'Employee', |
|||
'contact_type_right': 'p' |
|||
}) |
|||
c2p_rel.write({'own_tab_left': True}) |
|||
c2p_rel.write({'own_tab_right': True}) |
|||
c2p_rel_typ = res_partner_relation_type_selection_model.search( |
|||
[('type_id', '=', c2p_rel.id)], limit=1).id |
|||
res_partner_relation_all_model.create({ |
|||
'this_partner_id': company.id, |
|||
'other_partner_id': employer.id, |
|||
'type_selection_id': c2p_rel_typ |
|||
}) |
|||
result = employer.with_context().fields_view_get() |
|||
# we check whether the company's res.partner form contains the |
|||
# appropriate views (inserted by fields_view_get |
|||
tree = etree.fromstring(result['arch']) |
|||
field = tree.xpath('field[@name="id"]') |
|||
self.assertTrue(field, 'Id field does not exist.') |
|||
relation_ids_value_right = getattr( |
|||
employer, |
|||
'relation_ids_own_tab_{}_right'.format(c2p_rel.id)) |
|||
self.assertTrue( |
|||
relation_ids_value_right, |
|||
'Relation was not found') |
|||
relation_ids_value_left = getattr( |
|||
company, 'relation_ids_own_tab_{}_left'.format(c2p_rel.id)) |
|||
self.assertTrue( |
|||
relation_ids_value_left, |
|||
'Left relation field was not found') |
@ -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"> |
|||
<data> |
|||
<field name="partner_category_left" position="after"> |
|||
<field name="own_tab_left" /> |
|||
</field> |
|||
<field name="partner_category_right" position="after"> |
|||
<field name="own_tab_right" /> |
|||
</field> |
|||
</data> |
|||
</field> |
|||
</record> |
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue