committed by
Ronald Portier
14 changed files with 914 additions and 0 deletions
-
65partner_multi_relation_parent/README.rst
-
4partner_multi_relation_parent/__init__.py
-
19partner_multi_relation_parent/__manifest__.py
-
48partner_multi_relation_parent/data/data.xml
-
134partner_multi_relation_parent/i18n/nl.po
-
131partner_multi_relation_parent/i18n/partner_multi_relation_parent.pot
-
6partner_multi_relation_parent/models/__init__.py
-
114partner_multi_relation_parent/models/res_partner_relation.py
-
167partner_multi_relation_parent/models/res_partner_relation_all.py
-
48partner_multi_relation_parent/models/res_partner_relation_type.py
-
BINpartner_multi_relation_parent/static/description/icon.png
-
4partner_multi_relation_parent/tests/__init__.py
-
156partner_multi_relation_parent/tests/test_partner_multi_relation_parent.py
-
18partner_multi_relation_parent/views/res_partner_relation_type.xml
@ -0,0 +1,65 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
=================================== |
|||
Parent contact Mapping in relations |
|||
=================================== |
|||
|
|||
This module maps automatically creates contact relations for contact |
|||
addresss of a partner. Inversely, you can create a contact relation between a |
|||
person and another partner, and the person will automatically become a |
|||
contact address for the other partner. A person may only have one contact |
|||
relation, because a partner may only have one parent. |
|||
|
|||
|
|||
|
|||
Known issues / Roadmap |
|||
====================== |
|||
|
|||
* hide/forbade the deletion of the "Is contact of" and "Has Contact" installed |
|||
relation types |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues |
|||
<https://github.com/OCA/partner_multi_relation/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. |
|||
|
|||
Credits |
|||
======= |
|||
|
|||
Images |
|||
------ |
|||
|
|||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Giovanni Francesco Capalbo <giovanni@therp.nl> |
|||
* Ronald Portier <ronald@therp.nl> |
|||
|
|||
Do not contact contributors directly about help with questions or problems |
|||
concerning this addon, but use the |
|||
`community mailing list <mailto:community@mail.odoo.com>`_ or the |
|||
`appropriate specialized mailinglist <https://odoo-community.org/groups>`_ |
|||
for help, and the bug tracker linked in `Bug Tracker`_ above for |
|||
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 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,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Therp BV <https://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
{ |
|||
"name": "Partner Contact Mapping in relations", |
|||
"version": "10.0.1.0.0", |
|||
"author": "Therp BV,Odoo Community Association (OCA)", |
|||
"license": "AGPL-3", |
|||
"category": "Customer Relationship Management", |
|||
"summary": "Show partner addresses also as relations", |
|||
"depends": [ |
|||
'partner_multi_relation', |
|||
], |
|||
"data": [ |
|||
'data/data.xml', |
|||
'views/res_partner_relation_type.xml', |
|||
], |
|||
"installable": True, |
|||
} |
@ -0,0 +1,48 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo noupdate="0"> |
|||
|
|||
<record |
|||
id="relation_type_parent_contact" |
|||
model="res.partner.relation.type" |
|||
> |
|||
<field name="name">Is contact of</field> |
|||
<field name="name_inverse">Has contact</field> |
|||
<field name="partner_type">contact</field> |
|||
<field name="partner_synchronization_active" eval="0" /> |
|||
<field name="handle_invalid_onchange">restrict</field> |
|||
</record> |
|||
|
|||
<record |
|||
id="relation_type_parent_invoice" |
|||
model="res.partner.relation.type" |
|||
> |
|||
<field name="name">Is invoice address for</field> |
|||
<field name="name_inverse">Has invoice address</field> |
|||
<field name="partner_type">invoice</field> |
|||
<field name="partner_synchronization_active" eval="0" /> |
|||
<field name="handle_invalid_onchange">restrict</field> |
|||
</record> |
|||
|
|||
<record |
|||
id="relation_type_parent_delivery" |
|||
model="res.partner.relation.type" |
|||
> |
|||
<field name="name">Is delivery address for</field> |
|||
<field name="name_inverse">Has delivery address</field> |
|||
<field name="partner_type">delivery</field> |
|||
<field name="partner_synchronization_active" eval="0" /> |
|||
<field name="handle_invalid_onchange">restrict</field> |
|||
</record> |
|||
|
|||
<record |
|||
id="relation_type_parent_other" |
|||
model="res.partner.relation.type" |
|||
> |
|||
<field name="name">Is alternative address for</field> |
|||
<field name="name_inverse">Has alternative address</field> |
|||
<field name="partner_type">other</field> |
|||
<field name="partner_synchronization_active" eval="0" /> |
|||
<field name="handle_invalid_onchange">restrict</field> |
|||
</record> |
|||
|
|||
</odoo> |
@ -0,0 +1,134 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * partner_multi_relation_parent |
|||
# |
|||
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: 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_parent |
|||
#: model:ir.model,name:partner_multi_relation_parent.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_parent |
|||
#: selection:res.partner.relation.type,partner_type:0 |
|||
msgid "Contact" |
|||
msgstr "Contact" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: code:addons/partner_multi_relation_parent/models/res_partner_relation_all.py:145 |
|||
#, python-format |
|||
msgid "Creating a relation for address with type %s is not allowed at self time." |
|||
msgstr "Het leggen van een connectie tussen partners van type %s is op dit moment niet toegestaan." |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: code:addons/partner_multi_relation_parent/models/res_partner_relation_all.py:74 |
|||
#, python-format |
|||
msgid "Creating a relation for address with type %s is not allowed at this time." |
|||
msgstr "Het aanmaken van een adres met type %s is op dit moment niet toegestaan." |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_parent.relation_type_parent_other |
|||
msgid "Has alternative address" |
|||
msgstr "Heeft alternatief adres" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_parent.relation_type_parent_contact |
|||
msgid "Has contact" |
|||
msgstr "Heeft contact" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_parent.relation_type_parent_delivery |
|||
msgid "Has delivery address" |
|||
msgstr "Heeft afleveradres" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_parent.relation_type_parent_invoice |
|||
msgid "Has invoice address" |
|||
msgstr "Heeft factuuradres" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model.fields,help:partner_multi_relation_parent.field_res_partner_relation_type_partner_type |
|||
msgid "If filled connections will be automatically created when partners of the specified type are linked to a parent.\n" |
|||
"Also the parent of the left contact will be updated when connections of this type are added or updated." |
|||
msgstr "Indien ingevuld, dan zullen er automatisch connecties aangemaakt worden wanneer een adres van dit type voor een relatie wordt aangemaakt.\n" |
|||
"Tevens zal de linker partner automatisch gedefinieerd worden als een adres van dit type voor de relatie aan de rechterkant van de connectie." |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: selection:res.partner.relation.type,partner_type:0 |
|||
msgid "Invoice address" |
|||
msgstr "Factuuradres" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name:partner_multi_relation_parent.relation_type_parent_other |
|||
msgid "Is alternative address for" |
|||
msgstr "Is een alternatief adres voor" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name:partner_multi_relation_parent.relation_type_parent_contact |
|||
msgid "Is contact of" |
|||
msgstr "Is contactadres voor" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name:partner_multi_relation_parent.relation_type_parent_delivery |
|||
msgid "Is delivery address for" |
|||
msgstr "Is afleveradres voor" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name:partner_multi_relation_parent.relation_type_parent_invoice |
|||
msgid "Is invoice address for" |
|||
msgstr "Is factuuradres voor" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: selection:res.partner.relation.type,partner_type:0 |
|||
msgid "Other address" |
|||
msgstr "Overig adres" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model,name:partner_multi_relation_parent.model_res_partner |
|||
msgid "Partner" |
|||
msgstr "Relatie" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model.fields,field_description:partner_multi_relation_parent.field_res_partner_relation_type_partner_type |
|||
msgid "Partner Address Type" |
|||
msgstr "Soort adres" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model,name:partner_multi_relation_parent.model_res_partner_relation_type |
|||
msgid "Partner Relation Type" |
|||
msgstr "Type connectie voor de relatie" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model,name:partner_multi_relation_parent.model_res_partner_relation |
|||
msgid "Partner relation" |
|||
msgstr "Connectie" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: selection:res.partner.relation.type,partner_type:0 |
|||
msgid "Shipping address" |
|||
msgstr "Afleveradres" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model.fields,field_description:partner_multi_relation_parent.field_res_partner_relation_type_partner_synchronization_active |
|||
msgid "Synchronize relations and addresses" |
|||
msgstr "Synchroniseer connecties en adressen" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model.fields,help:partner_multi_relation_parent.field_res_partner_relation_type_partner_synchronization_active |
|||
msgid "This field can only be true if Partner Address Type filled.\n" |
|||
" When enabled will make sure that for all these connections the left partner will have the right partner as parent." |
|||
msgstr "Dit veld kan alleen aangevinkt worden als soort adres voor relatie gevuld is." |
|||
" Indien aangevinkt, dan zullen voor alle connecties van dit type de linker partner als adres verschijnen bij de rechter partner." |
|||
|
@ -0,0 +1,131 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * partner_multi_relation_parent |
|||
# |
|||
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_parent |
|||
#: model:ir.model,name:partner_multi_relation_parent.model_res_partner_relation_all |
|||
msgid "All (non-inverse + inverse) relations between partners" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: selection:res.partner.relation.type,partner_type:0 |
|||
msgid "Contact" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: code:addons/partner_multi_relation_parent/models/res_partner_relation_all.py:145 |
|||
#, python-format |
|||
msgid "Creating a relation for address with type %s is not allowed at self time." |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: code:addons/partner_multi_relation_parent/models/res_partner_relation_all.py:74 |
|||
#, python-format |
|||
msgid "Creating a relation for address with type %s is not allowed at this time." |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_parent.relation_type_parent_other |
|||
msgid "Has alternative address" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_parent.relation_type_parent_contact |
|||
msgid "Has contact" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_parent.relation_type_parent_delivery |
|||
msgid "Has delivery address" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name_inverse:partner_multi_relation_parent.relation_type_parent_invoice |
|||
msgid "Has invoice address" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model.fields,help:partner_multi_relation_parent.field_res_partner_relation_type_partner_type |
|||
msgid "If filled connections will be automatically created when partners of the specified type are linked to a parent.\n" |
|||
"Also the parent of the left contact will be updated when connections of this type are added or updated." |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: selection:res.partner.relation.type,partner_type:0 |
|||
msgid "Invoice address" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name:partner_multi_relation_parent.relation_type_parent_other |
|||
msgid "Is alternative address for" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name:partner_multi_relation_parent.relation_type_parent_contact |
|||
msgid "Is contact of" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name:partner_multi_relation_parent.relation_type_parent_delivery |
|||
msgid "Is delivery address for" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:res.partner.relation.type,name:partner_multi_relation_parent.relation_type_parent_invoice |
|||
msgid "Is invoice address for" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: selection:res.partner.relation.type,partner_type:0 |
|||
msgid "Other address" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model,name:partner_multi_relation_parent.model_res_partner |
|||
msgid "Partner" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model.fields,field_description:partner_multi_relation_parent.field_res_partner_relation_type_partner_type |
|||
msgid "Partner Address Type" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model,name:partner_multi_relation_parent.model_res_partner_relation_type |
|||
msgid "Partner Relation Type" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model,name:partner_multi_relation_parent.model_res_partner_relation |
|||
msgid "Partner relation" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: selection:res.partner.relation.type,partner_type:0 |
|||
msgid "Shipping address" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model.fields,field_description:partner_multi_relation_parent.field_res_partner_relation_type_partner_synchronization_active |
|||
msgid "Synchronize relations and addresses" |
|||
msgstr "" |
|||
|
|||
#. module: partner_multi_relation_parent |
|||
#: model:ir.model.fields,help:partner_multi_relation_parent.field_res_partner_relation_type_partner_synchronization_active |
|||
msgid "This field can only be true if Partner Address Type filled.\n" |
|||
" When enabled will make sure that for all these connections the left partner will have the right partner as parent." |
|||
msgstr "" |
|||
|
@ -0,0 +1,6 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Therp BV <https://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_relation_all |
|||
from . import res_partner_relation |
@ -0,0 +1,114 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Therp BV <https://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from openerp import _, api, models |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class ResPartnerRelation(models.Model): |
|||
_inherit = 'res.partner.relation' |
|||
|
|||
@api.multi |
|||
def write(self, vals): |
|||
"""Synchronize parent_id in left partner with connection. |
|||
|
|||
- If changed to non contact type, clear parent_id in partner; |
|||
- If changed to contact type, set parent_id and contact type |
|||
in partner. |
|||
""" |
|||
type_model = self.env['res.partner.relation.type'] |
|||
partner_model = self.env['res.partner'] |
|||
vals_type = 'type_id' in vals and \ |
|||
type_model.browse(vals['type_id']) or False |
|||
vals_left_partner = 'left_partner_id' in vals and \ |
|||
partner_model.browse(vals['left_partner_id']) or False |
|||
vals_right_partner = 'right_partner_id' in vals and \ |
|||
partner_model.browse(vals['right_partner_id']) or False |
|||
for this in self: |
|||
# Determine old and new type |
|||
old_type = this.type_id |
|||
new_type = vals_type or old_type |
|||
# First handle simple case: no address type involved |
|||
if not old_type.partner_type and not new_type.partner_type: |
|||
super(ResPartnerRelation, this).write(vals) |
|||
continue |
|||
# Store existing values |
|||
existing_left_partner = this.left_partner_id |
|||
existing_right_partner = this.right_partner_id |
|||
left_partner = vals_left_partner or existing_left_partner |
|||
right_partner = vals_right_partner or existing_right_partner |
|||
# Second relatively simple case is where non address |
|||
# connection is replaced by address connection |
|||
if not old_type.partner_type: |
|||
# Unlink existing connection |
|||
super(ResPartnerRelation, this).unlink() |
|||
# Create new connection |
|||
left_partner.write({ |
|||
'type': new_type.partner_type, |
|||
'parent_id': right_partner.id, |
|||
}) |
|||
continue |
|||
# Third handle case where address connection is changed into |
|||
# regular connection: |
|||
if not new_type.partner_type: |
|||
# Clear existing parent: |
|||
existing_left_partner.write({ |
|||
'parent_id': False, |
|||
}) |
|||
# Now create new connection: |
|||
vals['left_partner_id'] = left_partner.id |
|||
vals['type_id'] = new_type.id |
|||
vals['right_partner_id'] = right_partner.id |
|||
super(ResPartnerRelation, this).create(vals) |
|||
continue |
|||
# If we get here, both old and new connection are for address: |
|||
# Check wether new type is already allowed: |
|||
if not new_type.partner_synchronization_active: |
|||
raise ValidationError( |
|||
_("Creating a relation for address with type %s is" |
|||
" not allowed at this time.") % |
|||
(new_type.partner_type, )) |
|||
# If left partner changed, clear parent on left partner: |
|||
if left_partner != existing_left_partner: |
|||
existing_left_partner.write({ |
|||
'parent_id': False, |
|||
}) |
|||
left_partner.write({ |
|||
'type': new_type.partner_type, |
|||
'parent_id': right_partner.id, |
|||
}) |
|||
return True |
|||
|
|||
@api.multi |
|||
def unlink(self): |
|||
"""Unlinking relations for address, means clearing parent_id.""" |
|||
for this in self: |
|||
if this.type_id.partner_type: |
|||
this.left_partner_id.write({ |
|||
'parent_id': False, |
|||
}) |
|||
continue |
|||
super(ResPartnerRelation, this).unlink() |
|||
return True |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Creating a relation for an address means updating parent.""" |
|||
type_model = self.env['res.partner.relation.type'] |
|||
partner_model = self.env['res.partner'] |
|||
relation_type = type_model.browse(vals['type_id']) |
|||
if relation_type.partner_type: |
|||
if not relation_type.partner_synchronization_active: |
|||
raise ValidationError( |
|||
_("Creating a relation for address with type %s is" |
|||
" not allowed at this time.") % |
|||
(relation_type.partner_type, )) |
|||
left_partner = partner_model.browse(vals['left_partner_id']) |
|||
left_partner.write({ |
|||
'type': relation_type.partner_type, |
|||
'parent_id': vals['right_partner_id'], |
|||
}) |
|||
# Return the left partner. |
|||
# Create in res_partner_relation_all will know what to do. |
|||
return left_partner |
|||
return super(ResPartnerRelation, self).create(vals) |
@ -0,0 +1,167 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from openerp import _, api, models |
|||
from openerp.exceptions import ValidationError |
|||
|
|||
from openerp.addons.partner_multi_relation.models.res_partner_relation_all \ |
|||
import register_select_specification |
|||
|
|||
|
|||
# Register relation from address partner to parent partner: |
|||
register_select_specification( |
|||
base_name='partner_address', |
|||
is_inverse=False, |
|||
select_sql="""\ |
|||
SELECT |
|||
(partner.id * %%(padding)s) + %(key_offset)s as ID, |
|||
'res.partner' AS res_model, |
|||
partner.id AS res_id, |
|||
partner.id AS left_partner_id, |
|||
partner.parent_id AS right_partner_id, |
|||
rprt.id AS type_id, |
|||
NULL AS date_start, |
|||
NULL AS date_end, |
|||
%(is_inverse)s AS is_inverse |
|||
FROM res_partner partner |
|||
JOIN res_partner_relation_type rprt ON partner.type = rprt.partner_type |
|||
WHERE NOT partner.parent_id IS NULL |
|||
AND rprt.partner_synchronization_active""") |
|||
|
|||
# Register relation from parent partner to address partner: |
|||
register_select_specification( |
|||
base_name='partner_address', |
|||
is_inverse=True, |
|||
select_sql="""\ |
|||
SELECT |
|||
(partner.id * %%(padding)s) + %(key_offset)s as ID, |
|||
'res.partner' AS res_model, |
|||
partner.id AS res_id, |
|||
partner.parent_id AS left_partner_id, |
|||
partner.id AS right_partner_id, |
|||
rprt.id AS type_id, |
|||
NULL AS date_start, |
|||
NULL AS date_end, |
|||
%(is_inverse)s AS is_inverse |
|||
FROM res_partner partner |
|||
JOIN res_partner_relation_type rprt ON partner.type = rprt.partner_type |
|||
WHERE NOT partner.parent_id IS NULL |
|||
AND rprt.partner_synchronization_active""") |
|||
|
|||
|
|||
class ResPartnerRelationAll(models.AbstractModel): |
|||
"""Show addresses as relations if so configured.""" |
|||
_inherit = 'res.partner.relation.all' |
|||
|
|||
def _get_active_selects(self): |
|||
"""Return selects actually to be used. |
|||
|
|||
Selects are registered from all modules PRESENT. But should only be |
|||
used to build view if module actually INSTALLED. |
|||
""" |
|||
return super(ResPartnerRelationAll, self)._get_active_selects() +\ |
|||
['partner_address', 'partner_address_inverse'] |
|||
|
|||
@api.model |
|||
def _compute_base_name(self, type_selection): |
|||
"""This will be overridden for each inherit model.""" |
|||
if type_selection.type_id.partner_type: |
|||
return 'partner_address' |
|||
return super(ResPartnerRelationAll, self)._compute_base_name( |
|||
type_selection) |
|||
|
|||
@api.model |
|||
def create_resource(self, vals, type_selection): |
|||
if self._compute_base_name(type_selection) != 'partner_address': |
|||
return super(ResPartnerRelationAll, self).create_resource( |
|||
vals, type_selection) |
|||
partner_model = self.env['res.partner'] |
|||
relation_type = type_selection.type_id |
|||
if not relation_type.partner_synchronization_active: |
|||
raise ValidationError( |
|||
_("Creating a relation for address with type %s is" |
|||
" not allowed at this time.") % |
|||
(relation_type.partner_type, )) |
|||
left_partner = partner_model.browse(vals['left_partner_id']) |
|||
left_partner.write({ |
|||
'type': relation_type.partner_type, |
|||
'parent_id': vals['right_partner_id']}) |
|||
return left_partner |
|||
|
|||
@api.multi |
|||
def write_resource(self, base_resource, vals): |
|||
"""Synchronize parent_id in left partner with connection. |
|||
|
|||
- If changed to non contact type, clear parent_id in partner; |
|||
- If changed to contact type, set parent_id and contact type |
|||
in partner. |
|||
""" |
|||
self.ensure_one() |
|||
# Determine old and new type |
|||
type_model = self.env['res.partner.relation.type'] |
|||
vals_type = 'type_id' in vals and \ |
|||
type_model.browse(vals['type_id']) or False |
|||
type_selection = self.type_selection_id |
|||
old_type = type_selection.type_id |
|||
new_type = vals_type or old_type |
|||
# If neither old, nor new type are for partner address, |
|||
# write can/should be handled by super method: |
|||
if not old_type.partner_type and not new_type.partner_type: |
|||
return super(ResPartnerRelationAll, self).write_resource( |
|||
base_resource, vals) |
|||
# We have to handle partner address: |
|||
partner_model = self.env['res.partner'] |
|||
vals_left_partner = 'left_partner_id' in vals and \ |
|||
partner_model.browse(vals['left_partner_id']) or False |
|||
vals_right_partner = 'right_partner_id' in vals and \ |
|||
partner_model.browse(vals['right_partner_id']) or False |
|||
# Store existing values |
|||
existing_left_partner = base_resource |
|||
existing_right_partner = base_resource.parent_id |
|||
left_partner = vals_left_partner or existing_left_partner |
|||
right_partner = vals_right_partner or existing_right_partner |
|||
# Relatively simple case is where non address |
|||
# connection is replaced by address connection |
|||
if not old_type.partner_type: |
|||
# Unlink existing connection |
|||
super(ResPartnerRelationAll, self).unlink() |
|||
# Create new connection |
|||
left_partner.write({ |
|||
'type': new_type.partner_type, |
|||
'parent_id': right_partner.id}) |
|||
return True |
|||
# Handle case where address connection is changed into |
|||
# regular connection: |
|||
if not new_type.partner_type: |
|||
# Clear existing parent: |
|||
existing_left_partner.write({'parent_id': False}) |
|||
# Now create new connection: |
|||
relation_model = self.env['res.partner.relation'] |
|||
vals['left_partner_id'] = left_partner.id |
|||
vals['type_id'] = new_type.id |
|||
vals['right_partner_id'] = right_partner.id |
|||
relation_model.create(vals) |
|||
return True |
|||
# If we get here, both old and new connection are for address: |
|||
# Check wether new type is already allowed: |
|||
if not new_type.partner_synchronization_active: |
|||
raise ValidationError( |
|||
_("Creating a relation for address with type %s is" |
|||
" not allowed at self time.") % |
|||
(new_type.partner_type, )) |
|||
# If left partner changed, clear parent on left partner: |
|||
existing_left_partner.write({'parent_id': False}) |
|||
left_partner.write({ |
|||
'type': new_type.partner_type, |
|||
'parent_id': right_partner.id}) |
|||
return True |
|||
|
|||
@api.multi |
|||
def unlink_resource(self, base_resource): |
|||
"""Deleting an address connection is clearing parent_id.""" |
|||
self.ensure_one() |
|||
type_selection = self.type_selection_id |
|||
if self._compute_base_name(type_selection) != 'partner_address': |
|||
return super(ResPartnerRelationAll, self).unlink_resource( |
|||
base_resource) |
|||
base_resource.write({'parent_id': False}) |
@ -0,0 +1,48 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
"""Define synchronization between relations and addresses.""" |
|||
from openerp import api, fields, models |
|||
|
|||
|
|||
class ResPartnerRelationType(models.Model): |
|||
"""Model that defines relation types that might exist between partners""" |
|||
_inherit = 'res.partner.relation.type' |
|||
|
|||
partner_type = fields.Selection( |
|||
# TODO: determine automatically from selection in res.partner |
|||
selection=[ |
|||
('contact', 'Contact'), |
|||
('invoice', 'Invoice address'), |
|||
('delivery', 'Shipping address'), |
|||
('other', 'Other address'), |
|||
], |
|||
string='Partner Address Type', |
|||
readonly=True, |
|||
help="If filled connections will be automatically created when" |
|||
" partners of the specified type are linked to a parent.\n" |
|||
"Also the parent of the left contact will be updated when" |
|||
" connections of this type are added or updated." |
|||
) |
|||
partner_synchronization_active = fields.Boolean( |
|||
string="Synchronize relations and addresses", |
|||
default=False, |
|||
help="This field can only be true if Partner Address Type filled.\n" |
|||
" When enabled will make sure that for all these connections" |
|||
" the left partner will have the right partner as parent." |
|||
) |
|||
|
|||
@api.multi |
|||
def write(self, vals): |
|||
"""For address relation types, you can only change active flag.""" |
|||
for this in self: |
|||
if not this.partner_type: |
|||
super(ResPartnerRelationType, this).write(vals) |
|||
continue |
|||
if 'partner_synchronization_active' not in vals: |
|||
continue # Do nothing |
|||
super(ResPartnerRelationType, this).write({ |
|||
'partner_synchronization_active': |
|||
vals['partner_synchronization_active'] |
|||
}) |
|||
return True |
After Width: 90 | Height: 90 | Size: 13 KiB |
@ -0,0 +1,4 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Therp BV <https://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from . import test_partner_multi_relation_parent |
@ -0,0 +1,156 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Therp BV <https://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from odoo.addons.partner_multi_relation.tests.test_partner_relation_common \ |
|||
import TestPartnerRelationCommon |
|||
|
|||
|
|||
class TestPartnerMultiRelationParent(TestPartnerRelationCommon): |
|||
|
|||
# By default it will be false, this makes it run after the modules are |
|||
# installed |
|||
post_install = True |
|||
|
|||
def count_relations( |
|||
self, this_partner_id=False, type_id=False, |
|||
other_partner_id=False, any_partner_id=False): |
|||
"""Count relations satifying criteria passed.""" |
|||
domain = [] |
|||
if this_partner_id: |
|||
domain.append(('this_partner_id', '=', this_partner_id)) |
|||
if type_id: |
|||
domain.append(('type_id', '=', type_id)) |
|||
if other_partner_id: |
|||
domain.append(('other_partner_id', '=', other_partner_id)) |
|||
if any_partner_id: |
|||
domain.append(('any_partner_id', '=', any_partner_id)) |
|||
if not domain: |
|||
return 0 |
|||
relation_all_model = self.env['res.partner.relation.all'] |
|||
return relation_all_model.search_count(domain) |
|||
|
|||
def test_address_changes(self): |
|||
"""Test wether changes in address are reflected in relations.""" |
|||
# make sure that existing contact relation type enabled for sync: |
|||
contact_type = self.env.ref( |
|||
'partner_multi_relation_parent.relation_type_parent_contact' |
|||
) |
|||
contact_type.write({'partner_synchronization_active': True}) |
|||
# create a contact for ngo , partner n03 |
|||
ngo_contact = self.partner_model.create({ |
|||
'name': '03 NGO ACCOUNTANT', |
|||
'is_company': False, |
|||
'ref': 'PR03C01', |
|||
'type': 'contact', |
|||
'parent_id': self.partner_03_ngo.id |
|||
}) |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=ngo_contact.id, |
|||
type_id=contact_type.id, |
|||
other_partner_id=ngo_contact.parent_id.id |
|||
), 1) |
|||
# then modify partner and verify it |
|||
old_parent_id = ngo_contact.parent_id.id |
|||
ngo_contact.write( |
|||
{'parent_id': self.partner_02_company.id} |
|||
) |
|||
# check no more relations with old_parent |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=ngo_contact.id, |
|||
type_id=contact_type.id, |
|||
other_partner_id=old_parent_id |
|||
), 0) |
|||
# check relations are there with current parent |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=ngo_contact.id, |
|||
type_id=contact_type.id, |
|||
other_partner_id=ngo_contact.parent_id.id |
|||
), 1) |
|||
# delete NGO ACCOUNTANT |
|||
old_id = ngo_contact.id |
|||
old_parent_id = ngo_contact.parent_id.id |
|||
ngo_contact.unlink() |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=old_id, |
|||
type_id=contact_type.id, |
|||
other_partner_id=old_parent_id |
|||
), 0) |
|||
|
|||
def test_relation_type_changes(self): |
|||
"""Test wether changes in address are reflected in relations.""" |
|||
# make sure that existing delivery relation type NOT enabled for sync: |
|||
delivery_type = self.env.ref( |
|||
'partner_multi_relation_parent.relation_type_parent_delivery' |
|||
) |
|||
delivery_type.write({'partner_synchronization_active': False}) |
|||
# create a delivery address for ngo , partner n03 |
|||
ngo_delivery = self.partner_model.create({ |
|||
'name': '03 NGO Delivery Address', |
|||
'is_company': False, |
|||
'ref': 'PR03D01', |
|||
'type': 'delivery', |
|||
'parent_id': self.partner_03_ngo.id |
|||
}) |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=ngo_delivery.id, |
|||
type_id=delivery_type.id, |
|||
other_partner_id=ngo_delivery.parent_id.id |
|||
), 0) |
|||
# after enabling delivery relation type, relations should be there: |
|||
delivery_type.write({'partner_synchronization_active': True}) |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=ngo_delivery.id, |
|||
type_id=delivery_type.id, |
|||
other_partner_id=ngo_delivery.parent_id.id |
|||
), 1) |
|||
|
|||
def test_relation_changes(self): |
|||
"""Test wether changes in relation are reflected in address. |
|||
|
|||
NB: left partner is the address partner, right partner the parent. |
|||
""" |
|||
# make sure that existing contact relation type enabled for sync: |
|||
contact_type = self.env.ref( |
|||
'partner_multi_relation_parent.relation_type_parent_contact') |
|||
contact_type.write({'partner_synchronization_active': True}) |
|||
# create a contact address, to be linked to ngo partner: |
|||
ngo_contact = self.partner_model.create({ |
|||
'name': '03 NGO ACCOUNTANT', |
|||
'is_company': False, |
|||
'ref': 'PR03C01', |
|||
}) |
|||
# Now create a contact address relation: |
|||
ngo_relation = self.relation_all_model.create({ |
|||
'this_partner_id': ngo_contact.id, |
|||
'type_id': contact_type.id, |
|||
'other_partner_id': self.partner_03_ngo.id}) |
|||
# Now the contact address should be linked to parent as contact: |
|||
self.assertEqual(ngo_contact.parent_id.name, self.partner_03_ngo.name) |
|||
self.assertEqual(ngo_contact.type, 'contact') |
|||
# Now link the contact address to another company: |
|||
old_parent_id = ngo_contact.parent_id.id |
|||
ngo_relation.write({'other_partner_id': self.partner_02_company.id}) |
|||
# check no more relations with old_parent |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=ngo_contact.id, |
|||
other_partner_id=old_parent_id), 0) |
|||
# check relations are there with current parent |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=ngo_contact.id, |
|||
other_partner_id=ngo_contact.parent_id.id), 1) |
|||
# Remove the relation altoghether: |
|||
old_parent_id = ngo_contact.parent_id.id |
|||
ngo_relation.unlink() |
|||
self.assertEqual( |
|||
self.count_relations( |
|||
this_partner_id=ngo_contact.id, |
|||
other_partner_id=old_parent_id), 0) |
|||
self.assertEqual(ngo_contact.parent_id.id, False) |
@ -0,0 +1,18 @@ |
|||
<?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 type="xml" name="arch"> |
|||
<field name="handle_invalid_onchange" position="after"> |
|||
<field name="partner_type" readonly="1" /> |
|||
<field name="partner_synchronization_active" /> |
|||
</field> |
|||
</field> |
|||
</record> |
|||
|
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue