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