Browse Source

Add module partner_multi_relation_parent

pull/493/head
Giovanni Francesco Capalbo 7 years ago
committed by Ronald Portier
parent
commit
e2fe24c458
  1. 65
      partner_multi_relation_parent/README.rst
  2. 4
      partner_multi_relation_parent/__init__.py
  3. 19
      partner_multi_relation_parent/__manifest__.py
  4. 48
      partner_multi_relation_parent/data/data.xml
  5. 134
      partner_multi_relation_parent/i18n/nl.po
  6. 131
      partner_multi_relation_parent/i18n/partner_multi_relation_parent.pot
  7. 6
      partner_multi_relation_parent/models/__init__.py
  8. 114
      partner_multi_relation_parent/models/res_partner_relation.py
  9. 167
      partner_multi_relation_parent/models/res_partner_relation_all.py
  10. 48
      partner_multi_relation_parent/models/res_partner_relation_type.py
  11. BIN
      partner_multi_relation_parent/static/description/icon.png
  12. 4
      partner_multi_relation_parent/tests/__init__.py
  13. 156
      partner_multi_relation_parent/tests/test_partner_multi_relation_parent.py
  14. 18
      partner_multi_relation_parent/views/res_partner_relation_type.xml

65
partner_multi_relation_parent/README.rst

@ -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.

4
partner_multi_relation_parent/__init__.py

@ -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

19
partner_multi_relation_parent/__manifest__.py

@ -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,
}

48
partner_multi_relation_parent/data/data.xml

@ -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>

134
partner_multi_relation_parent/i18n/nl.po

@ -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."

131
partner_multi_relation_parent/i18n/partner_multi_relation_parent.pot

@ -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 ""

6
partner_multi_relation_parent/models/__init__.py

@ -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

114
partner_multi_relation_parent/models/res_partner_relation.py

@ -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)

167
partner_multi_relation_parent/models/res_partner_relation_all.py

@ -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})

48
partner_multi_relation_parent/models/res_partner_relation_type.py

@ -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

BIN
partner_multi_relation_parent/static/description/icon.png

After

Width: 90  |  Height: 90  |  Size: 13 KiB

4
partner_multi_relation_parent/tests/__init__.py

@ -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

156
partner_multi_relation_parent/tests/test_partner_multi_relation_parent.py

@ -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)

18
partner_multi_relation_parent/views/res_partner_relation_type.xml

@ -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>
Loading…
Cancel
Save