Browse Source

[7.0] [FIX] Fix issue in partner_relations. (#211)

There was a problem with the code to determine whether the right hand partner in a
relation was the active partner.
7.0
Ronald Portier 8 years ago
committed by Pedro M. Baeza
parent
commit
643511e835
  1. 21
      partner_relations/__init__.py
  2. 33
      partner_relations/__openerp__.py
  3. 21
      partner_relations/model/__init__.py
  4. 35
      partner_relations/model/res_partner.py
  5. 93
      partner_relations/model/res_partner_relation.py
  6. 54
      partner_relations/model/res_partner_relation_all.py
  7. 24
      partner_relations/model/res_partner_relation_type.py
  8. 88
      partner_relations/model/res_partner_relation_type_selection.py

21
partner_relations/__init__.py

@ -1,21 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# © 2013-2017 Therp BV <http://therp.nl>.
# License AGPL-3.0 or later <http://www.gnu.org/licenses/agpl.html>.
from . import model

33
partner_relations/__openerp__.py

@ -1,27 +1,11 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# © 2013-2017 Therp BV <http://therp.nl>.
# License AGPL-3.0 or later <http://www.gnu.org/licenses/agpl.html>.
{
"name": "Partner relations",
"version": "1.1",
"version": "7.0.1.1.1",
"author": "Therp BV,Odoo Community Association (OCA)",
"license": "AGPL-3",
"complexity": "normal",
"description": """
Introduction
@ -83,15 +67,6 @@ date.""",
'view/menu.xml',
'security/ir.model.access.csv',
],
"js": [
],
"css": [
],
"qweb": [
],
"auto_install": False,
"installable": True,
"external_dependencies": {
'python': [],
},
}

21
partner_relations/model/__init__.py

@ -1,23 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# © 2013-2017 Therp BV <http://therp.nl>.
# License AGPL-3.0 or later <http://www.gnu.org/licenses/agpl.html>.
from . import res_partner
from . import res_partner_relation
from . import res_partner_relation_type

35
partner_relations/model/res_partner.py

@ -1,25 +1,8 @@
# -*- coding: utf-8 -*-
'''Extend res.partner model'''
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# © 2013-2017 Therp BV <http://therp.nl>.
# License AGPL-3.0 or later <http://www.gnu.org/licenses/agpl.html>.
import time
from openerp.osv import orm, fields
from openerp.osv.expression import is_leaf, AND, OR, FALSE_LEAF
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
@ -31,12 +14,12 @@ class ResPartner(orm.Model):
def _get_relation_ids_select(self, cr, uid, ids, field_name, arg,
context=None):
'''return the partners' relations as tuple
(id, left_partner_id, right_partner_id)'''
"""return the partners' relations as tuple
(id, left_partner_id, right_partner_id)"""
cr.execute(
'''select id, left_partner_id, right_partner_id
"""select id, left_partner_id, right_partner_id
from res_partner_relation
where (left_partner_id in %s or right_partner_id in %s)''' +
where (left_partner_id in %s or right_partner_id in %s)""" +
' order by ' + self.pool['res.partner.relation']._order,
(tuple(ids), tuple(ids))
)
@ -44,7 +27,7 @@ class ResPartner(orm.Model):
def _get_relation_ids(
self, cr, uid, ids, field_name, arg, context=None):
'''getter for relation_ids'''
"""getter for relation_ids"""
if context is None:
context = {}
result = dict([(i, []) for i in ids])
@ -60,7 +43,7 @@ class ResPartner(orm.Model):
def _set_relation_ids(
self, cr, uid, ids, dummy_name, field_value, dummy_arg,
context=None):
'''setter for relation_ids'''
"""setter for relation_ids"""
if context is None:
context = {}
relation_obj = self.pool.get('res.partner.relation')

93
partner_relations/model/res_partner_relation.py

@ -1,31 +1,13 @@
# -*- coding: utf-8 -*-
'''Define model res.partner.relation'''
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# © 2013-2017 Therp BV <http://therp.nl>.
# License AGPL-3.0 or later <http://www.gnu.org/licenses/agpl.html>.
from openerp.osv.orm import Model, except_orm
from openerp.osv import fields
from openerp.tools.translate import _
class ResPartnerRelation(Model):
'''Model res.partner.relation is used to describe all links or relations
"""Model res.partner.relation is used to describe all links or relations
between partners in the database.
In many parts of the code we have to know whether the active partner is
@ -35,23 +17,14 @@ class ResPartnerRelation(Model):
Because the active partner is crucial for the working of partner
relationships, we make sure on the res.partner model that the partner id
is set in the context where needed.
'''
"""
_name = 'res.partner.relation'
_description = 'Partner relation'
_order = 'active desc, date_start desc, date_end desc'
def _on_right_partner(self, cr, uid, right_partner_id, context=None):
'''Determine wether functions are called in a situation where the
active partner is the right partner. Default False!
'''
if (context and 'active_ids' in context and
right_partner_id in context.get('active_ids', [])):
return True
return False
def _correct_vals(self, cr, uid, vals, context=None):
'''Fill type and left and right partner id, according to wether
we have a normal relation type or an inverse relation type'''
"""Fill type and left and right partner id, according to wether
we have a normal relation type or an inverse relation type"""
vals = vals.copy()
# If type_selection_id ends in 1, it is a reverse relation type
if 'type_selection_id' in vals:
@ -75,13 +48,16 @@ class ResPartnerRelation(Model):
def _get_computed_fields(
self, cr, uid, ids, field_names, arg, context=None):
'''Return a dictionary of dictionaries, with for every partner for
ids, the computed values.'''
"""Return a dictionary of dictionaries, with for every partner for
ids, the computed values."""
def get_values(self, dummy_field_names, dummy_arg, context=None):
'''Get computed values for record'''
"""Get computed values for record"""
values = {}
on_right_partner = self._on_right_partner(
cr, uid, self.right_partner_id.id, context=context)
on_right_partner = (
'active_ids' in context and
self.right_partner_id.id in context.get('active_ids', []) or
False
)
# type_selection_id
values['type_selection_id'] = (
((self.type_id.id) * 10) + (on_right_partner and 1 or 0))
@ -99,26 +75,27 @@ class ResPartnerRelation(Model):
values['is_relation_future'] = self.date_start > today
return values
context = context or {}
return dict([
(i.id, get_values(i, field_names, arg, context=context))
for i in self.browse(cr, uid, ids, context=context)
])
def write(self, cr, uid, ids, vals, context=None):
'''Override write to correct values, before being stored.'''
"""Override write to correct values, before being stored."""
vals = self._correct_vals(cr, uid, vals, context=context)
return super(ResPartnerRelation, self).write(
cr, uid, ids, vals, context=context)
def create(self, cr, uid, vals, context=None):
'''Override create to correct values, before being stored.'''
"""Override create to correct values, before being stored."""
vals = self._correct_vals(cr, uid, vals, context=context)
return super(ResPartnerRelation, self).create(
cr, uid, vals, context=context)
def on_change_type_selection_id(
self, cr, uid, dummy_ids, type_selection_id, context=None):
'''Set domain on partner_id_display, when selection a relation type'''
"""Set domain on partner_id_display, when selection a relation type"""
result = {
'domain': {'partner_id_display': []},
'value': {'type_id': False}
@ -198,13 +175,12 @@ class ResPartnerRelation(Model):
),
'active': fields.boolean('Active'),
}
_defaults = {
'active': True,
}
def _check_dates(self, cr, uid, ids, context=None):
'''End date should not be before start date, if noth filled'''
"""End date should not be before start date, if noth filled"""
for line in self.browse(cr, uid, ids, context=context):
if line.date_start and line.date_end:
if line.date_start > line.date_end:
@ -212,7 +188,7 @@ class ResPartnerRelation(Model):
return True
def _check_partner_type_left(self, cr, uid, ids, context=None):
'''Check left partner for required company or person'''
"""Check left partner for required company or person"""
for this in self.browse(cr, uid, ids, context=context):
ptype = this.type_id.contact_type_left
company = this.left_partner_id.is_company
@ -221,7 +197,7 @@ class ResPartnerRelation(Model):
return True
def _check_partner_type_right(self, cr, uid, ids, context=None):
'''Check right partner for required company or person'''
"""Check right partner for required company or person"""
for this in self.browse(cr, uid, ids, context=context):
ptype = this.type_id.contact_type_right
company = this.right_partner_id.is_company
@ -230,15 +206,15 @@ class ResPartnerRelation(Model):
return True
def _check_not_with_self(self, cr, uid, ids, context=None):
'''Not allowed to link partner to same partner'''
"""Not allowed to link partner to same partner"""
for this in self.browse(cr, uid, ids, context=context):
if this.left_partner_id == this.right_partner_id:
return False
return True
def _check_relation_uniqueness(self, cr, uid, ids, context=None):
'''Forbid multiple active relations of the same type between the same
partners'''
"""Forbid multiple active relations of the same type between the same
partners"""
for this in self.browse(cr, uid, ids, context=context):
if not this.active:
continue
@ -250,17 +226,21 @@ class ResPartnerRelation(Model):
('right_partner_id', '=', this.right_partner_id.id),
]
if this.date_start:
domain += ['|', ('date_end', '=', False),
('date_end', '>=', this.date_start)]
domain += [
'|', ('date_end', '=', False),
('date_end', '>=', this.date_start),
]
if this.date_end:
domain += ['|', ('date_start', '=', False),
('date_start', '<=', this.date_end)]
domain += [
'|', ('date_start', '=', False),
('date_start', '<=', this.date_end),
]
if self.search(cr, uid, domain, context=context):
raise except_orm(
_('Overlapping relation'),
_('There is already a similar relation '
'with overlapping dates'))
'with overlapping dates')
)
return True
_constraints = [
@ -292,12 +272,13 @@ class ResPartnerRelation(Model):
]
def get_action_related_partners(self, cr, uid, ids, context=None):
'''return a window action showing a list of partners taking part in the
"""return a window action showing a list of partners taking part in the
relations names by ids. Context key 'partner_relations_show_side'
determines if we show 'left' side, 'right' side or 'all' (default)
partners.
If active_model is res.partner.relation.all, left=this and
right=other'''
right=other
"""
if context is None:
context = {}

54
partner_relations/model/res_partner_relation_all.py

@ -1,28 +1,12 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2014 Therp BV (<http://therp.nl>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# © 2013-2017 Therp BV <http://therp.nl>.
# License AGPL-3.0 or later <http://www.gnu.org/licenses/agpl.html>.
from psycopg2.extensions import AsIs
from openerp.osv.orm import Model
from openerp.osv import fields
from openerp.tools import drop_view_if_exists
from .res_partner_relation_type_selection\
import ResPartnerRelationTypeSelection
from .res_partner_relation_type_selection import _RECORD_TYPES
class ResPartnerRelationAll(Model):
@ -32,7 +16,7 @@ class ResPartnerRelationAll(Model):
_description = 'All (non-inverse + inverse) relations between partners'
_additional_view_fields = []
'''append to this list if you added fields to res_partner_relation that
"""append to this list if you added fields to res_partner_relation that
you need in this model and related fields are not adequate (ie for sorting)
You must use the same name as in res_partner_relation.
Don't overwrite this list in your declatarion but append in _auto_init:
@ -45,15 +29,16 @@ class ResPartnerRelationAll(Model):
_columns = {
'my_field': ....
}
'''
"""
def _auto_init(self, cr, context=None):
"""Create view instead of table."""
drop_view_if_exists(cr, self._table)
additional_view_fields = ','.join(self._additional_view_fields)
additional_view_fields = (',' + additional_view_fields)\
if additional_view_fields else ''
cr.execute(
'''create or replace view %s as
"""create or replace view %s as
select
id * 10 as id,
id as relation_id,
@ -79,20 +64,23 @@ class ResPartnerRelationAll(Model):
active,
type_id * 10 + 1
%s
from res_partner_relation''' % (
self._table,
additional_view_fields,
additional_view_fields,
from res_partner_relation
""",
params=(
AsIs(self._table),
AsIs(additional_view_fields),
AsIs(additional_view_fields),
)
)
return super(ResPartnerRelationAll, self)._auto_init(
cr, context=context)
_columns = {
'record_type': fields.selection(
ResPartnerRelationTypeSelection._RECORD_TYPES, 'Record type',
readonly=True),
_RECORD_TYPES,
'Record type',
readonly=True,
),
'relation_id': fields.many2one(
'res.partner.relation', 'Relation', readonly=True),
'type_id': fields.many2one(
@ -110,6 +98,7 @@ class ResPartnerRelationAll(Model):
}
def name_get(self, cr, uid, ids, context=None):
"""Create name from both partners and relation."""
return dict([
(this.id, '%s %s %s' % (
this.this_partner_id.name,
@ -119,7 +108,8 @@ class ResPartnerRelationAll(Model):
for this in self.browse(cr, uid, ids, context=context)])
def write(self, cr, uid, ids, vals, context=None):
'''divert non-problematic writes to underlying table'''
"""divert non-problematic writes to underlying table"""
# pylint: disable=W8106
return self.pool['res.partner.relation'].write(
cr, uid,
[i / 10 for i in ids],

24
partner_relations/model/res_partner_relation_type.py

@ -1,30 +1,12 @@
# -*- coding: utf-8 -*-
'''Define model res.partner.relation.type'''
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# © 2013-2017 Therp BV <http://therp.nl>.
# License AGPL-3.0 or later <http://www.gnu.org/licenses/agpl.html>.
from openerp.osv.orm import Model
from openerp.osv import fields
class ResPartnerRelationType(Model):
'''Model that defines relation types that might exist between partners'''
"""Model that defines relation types that might exist between partners"""
_name = 'res.partner.relation.type'
_description = 'Parter relation type'
_order = 'name'

88
partner_relations/model/res_partner_relation_type_selection.py

@ -1,65 +1,61 @@
# -*- coding: UTF-8 -*-
'''
Created on 23 may 2014
# -*- coding: utf-8 -*-
# © 2014-2017 Therp BV <http://therp.nl>.
# License AGPL-3.0 or later <http://www.gnu.org/licenses/agpl.html>.
from psycopg2.extensions import AsIs
@author: Ronald Portier, Therp
rportier@therp.nl
http://www.therp.nl
For the model defined here _auto is set to False to prevent creating a
database file. All i/o operations are overridden to use a sql SELECT that
takes data from res_partner_connection_type where each type is included in the
result set twice, so it appears that the connection type and the inverse
type are separate records..
The original function _auto_init is still called because this function
normally (if _auto == True) not only creates the db tables, but it also takes
care of registering all fields in ir_model_fields. This is needed to make
the field labels translatable.
example content for last lines of _statement:
select id, record_type,
customer_id, customer_name, customer_city, customer_zip, customer_street,
caller_id, caller_name, caller_phone, caller_fax, caller_email
from FULL_LIST as ResPartnerRelationTypeSelection where record_type = 'c'
ORDER BY ResPartnerRelationTypeSelection.customer_name asc,
ResPartnerRelationTypeSelection.caller_name asc;
'''
from openerp.osv import fields
from openerp.osv import orm
from openerp.tools import drop_view_if_exists
from openerp.addons.partner_relations.model.res_partner_relation_type\
import ResPartnerRelationType
from .res_partner_relation_type import ResPartnerRelationType
class ResPartnerRelationTypeSelection(orm.Model):
'''Virtual relation types'''
_RECORD_TYPES = [
('a', 'Type'),
('b', 'Inverse type'),
]
_RECORD_TYPES = [
('a', 'Type'),
('b', 'Inverse type'),
]
class ResPartnerRelationTypeSelection(orm.Model):
"""Virtual relation types.
For the model defined here _auto is set to False to prevent creating a
database file. All i/o operations are overridden to use a sql SELECT that
takes data from res_partner_connection_type where each type is included
in the result set twice, so it appears that the connection type and
the inverse type are separate records..
The original function _auto_init is still called because this function
normally (if _auto == True) not only creates the db tables, but it also
takes care of registering all fields in ir_model_fields. This is needed
to make the field labels translatable.
example content for last lines of _statement:
select id, record_type,
customer_id, customer_name, customer_city, customer_zip, customer_street,
caller_id, caller_name, caller_phone, caller_fax, caller_email
from FULL_LIST as ResPartnerRelationTypeSelection where record_type = 'c'
ORDER BY ResPartnerRelationTypeSelection.customer_name asc,
ResPartnerRelationTypeSelection.caller_name asc;
"""
_auto = False # Do not try to create table in _auto_init(..)
_log_access = False
def get_type_from_selection_id(self, cr, uid, selection_id):
'''Selection id ic computed from id of underlying type and the
"""Selection id ic computed from id of underlying type and the
kind of record. This function does the inverse computation to give
back the original type id, and about the record type.'''
back the original type id, and about the record type."""
type_id = selection_id / 10
is_reverse = (selection_id % 10) > 0
return (type_id, is_reverse)
def _auto_init(self, cr, context=None):
"""Create view instead of table."""
drop_view_if_exists(cr, self._table)
# TODO: we lose field value's translations here.
# probably we need to patch ir_translation.get_source for that
# to get res_partner_relation_type's translations
cr.execute(
'''create or replace view %s as
"""create or replace view %s as
select
id * 10 as id,
id as type_id,
@ -79,15 +75,18 @@ class ResPartnerRelationTypeSelection(orm.Model):
contact_type_left,
partner_category_right,
partner_category_left
from res_partner_relation_type''' % self._table)
from res_partner_relation_type
""",
params=(
AsIs(self._table),
)
)
return super(ResPartnerRelationTypeSelection, self)._auto_init(
cr, context=context)
def _search_partner_category_this(self, cr, uid, obj, field_name, args,
context=None):
def _search_partner_category_this(
self, cr, uid, obj, field_name, args, context=None):
category_ids = []
for arg in args:
if isinstance(arg, tuple) and arg[0] == field_name\
and (arg[1] == '=' or arg[1] == 'in'):
@ -95,7 +94,6 @@ class ResPartnerRelationTypeSelection(orm.Model):
for delta in arg[2]:
if delta[0] == 6:
category_ids.extend(delta[2])
if category_ids:
return [
'|',

Loading…
Cancel
Save