Browse Source

Fix Read Write, Create and Unlink for realtion_all

pull/103/head
Sandy Carter 10 years ago
parent
commit
06e071f6de
  1. 16
      partner_relations/model/__init__.py
  2. 13
      partner_relations/model/res_partner.py
  3. 117
      partner_relations/model/res_partner_relation.py
  4. 129
      partner_relations/model/res_partner_relation_all.py
  5. 17
      partner_relations/model/res_partner_relation_type.py
  6. 37
      partner_relations/model/res_partner_relation_type_selection.py
  7. 2
      partner_relations/view/res_partner.xml
  8. 41
      partner_relations/view/res_partner_relation.xml
  9. 63
      partner_relations/view/res_partner_relation_all.xml

16
partner_relations/model/__init__.py

@ -18,8 +18,22 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
PADDING = 10
def get_partner_type(partner):
"""Get partner type for relation.
:param partner: a res.partner either a company or not
:return: 'c' for company or 'p' for person
:rtype: str
"""
return 'c' if partner.is_company else 'p'
from . import res_partner
from . import res_partner_relation
from . import res_partner_relation_type
from . import res_partner_relation_type_selection
from . import res_partner_relation_all
from . import res_partner_relation_type_selection

13
partner_relations/model/res_partner.py

@ -112,9 +112,10 @@ class ResPartner(models.Model):
if arg[1] == '=' and isinstance(arg[2], (long, int)):
relation_type_selection_ids.append(arg[2])
elif arg[1] == '!=' and isinstance(arg[2], (long, int)):
type_id, is_inverse = relation_type_selection\
.get_type_from_selection_id(
cr, uid, arg[2])
type_id, is_inverse = (
relation_type_selection.browse(arg[2])
.get_type_from_selection_id()
)
result = OR([
result,
[
@ -144,9 +145,9 @@ class ResPartner(models.Model):
result = AND([result, [FALSE_LEAF]])
for relation_type_selection_id in relation_type_selection_ids:
type_id, is_inverse = relation_type_selection\
.get_type_from_selection_id(
cr, uid, relation_type_selection_id)
type_id, is_inverse = (
relation_type_selection_id.get_type_from_selection_id()
)
result = OR([
result,

117
partner_relations/model/res_partner_relation.py

@ -19,12 +19,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv.orm import Model, except_orm
from openerp.osv import fields
from openerp.tools.translate import _
from openerp import osv, models, fields, api, exceptions, _
class ResPartnerRelation(Model):
from . import get_partner_type
class ResPartnerRelation(models.Model):
'''Model res.partner.relation is used to describe all links or relations
between partners in the database.
@ -40,6 +41,27 @@ class ResPartnerRelation(Model):
_description = 'Partner relation'
_order = 'active desc, date_start desc, date_end desc'
left_contact_type = fields.Selection(
lambda s: s.env['res.partner.relation.type']._get_partner_types(),
'Left Partner Type',
compute='_get_partner_type',
store=True,
)
right_contact_type = fields.Selection(
lambda s: s.env['res.partner.relation.type']._get_partner_types(),
'Right Partner Type',
compute='_get_partner_type',
store=True,
)
@api.one
@api.depends('left_partner_id', 'right_partner_id')
def _get_partner_type(self):
self.left_contact_type = get_partner_type(self.left_partner_id)
self.right_contact_type = get_partner_type(self.right_partner_id)
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!
@ -49,28 +71,38 @@ class ResPartnerRelation(Model):
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'''
def _correct_vals(self, vals):
"""Fill type and left and right partner id, according to whether
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:
prts_model = self.pool['res.partner.relation.type.selection']
prts_model = self.env['res.partner.relation.type.selection']
type_selection_id = vals['type_selection_id']
(type_id, is_reverse) = (
prts_model.get_type_from_selection_id(
cr, uid, type_selection_id))
prts_model.browse(type_selection_id).
get_type_from_selection_id()
)
vals['type_id'] = type_id
if context.get('active_id'):
if self._context.get('active_id'):
if is_reverse:
vals['right_partner_id'] = context['active_id']
vals['right_partner_id'] = self._context['active_id']
else:
vals['left_partner_id'] = context['active_id']
vals['left_partner_id'] = self._context['active_id']
if vals.get('partner_id_display'):
if is_reverse:
vals['left_partner_id'] = vals['partner_id_display']
else:
vals['right_partner_id'] = vals['partner_id_display']
if vals.get('other_partner_id'):
if is_reverse:
vals['left_partner_id'] = vals['other_partner_id']
else:
vals['right_partner_id'] = vals['other_partner_id']
del vals['other_partner_id']
if vals.get('contact_type'):
del vals['contact_type']
return vals
def _get_computed_fields(
@ -90,12 +122,6 @@ class ResPartnerRelation(Model):
if on_right_partner
else self.right_partner_id.id
)
# is_relation_expired
today = fields.date.context_today(self, cr, uid, context=context)
values['is_relation_expired'] = (
self.date_end and (self.date_end < today))
# is_relation_future
values['is_relation_future'] = self.date_start > today
return values
return dict([
@ -103,17 +129,17 @@ class ResPartnerRelation(Model):
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.'''
vals = self._correct_vals(cr, uid, vals, context=context)
return super(ResPartnerRelation, self).write(
cr, uid, ids, vals, context=context)
@api.multi
def write(self, vals):
"""Override write to correct values, before being stored."""
vals = self._correct_vals(vals)
return super(ResPartnerRelation, self).write(vals)
def create(self, cr, uid, vals, context=None):
'''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)
@api.model
def create(self, vals):
"""Override create to correct values, before being stored."""
vals = self._correct_vals(vals)
return super(ResPartnerRelation, self).create(vals)
def on_change_type_selection_id(
self, cr, uid, dummy_ids, type_selection_id, context=None):
@ -156,46 +182,32 @@ class ResPartnerRelation(Model):
return result
_columns = {
'left_partner_id': fields.many2one(
'left_partner_id': osv.fields.many2one(
'res.partner', string='Left partner', required=True,
auto_join=True, ondelete='cascade'),
'right_partner_id': fields.many2one(
'right_partner_id': osv.fields.many2one(
'res.partner', string='Right partner', required=True,
auto_join=True, ondelete='cascade'),
'type_id': fields.many2one(
'type_id': osv.fields.many2one(
'res.partner.relation.type', string='Type', required=True,
auto_join=True),
'date_start': fields.date('Starting date'),
'date_end': fields.date('Ending date'),
'type_selection_id': fields.function(
'date_start': osv.fields.date('Starting date'),
'date_end': osv.fields.date('Ending date'),
'type_selection_id': osv.fields.function(
_get_computed_fields,
multi="computed_fields",
fnct_inv=lambda *args: None,
type='many2one', obj='res.partner.relation.type.selection',
string='Type',
),
'partner_id_display': fields.function(
'partner_id_display': osv.fields.function(
_get_computed_fields,
multi="computed_fields",
fnct_inv=lambda *args: None,
type='many2one', obj='res.partner',
string='Partner'
),
'is_relation_expired': fields.function(
_get_computed_fields,
multi="computed_fields",
type='boolean',
method=True,
string='Relation is expired',
),
'is_relation_future': fields.function(
_get_computed_fields,
multi="computed_fields",
type='boolean',
method=True,
string='Relation is in the future',
),
'active': fields.boolean('Active'),
'active': osv.fields.boolean('Active'),
}
_defaults = {
@ -255,8 +267,7 @@ class ResPartnerRelation(Model):
domain += ['|', ('date_start', '=', False),
('date_start', '<=', this.date_end)]
if self.search(cr, uid, domain, context=context):
raise except_orm(
_('Overlapping relation'),
raise exceptions.Warning(
_('There is already a similar relation '
'with overlapping dates'))

129
partner_relations/model/res_partner_relation_all.py

@ -18,24 +18,26 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv.orm import Model
from openerp.osv import fields
from openerp import osv, models, fields, api
from openerp.tools import drop_view_if_exists
from .res_partner_relation_type_selection\
import ResPartnerRelationTypeSelection
from .res_partner_relation_type_selection import \
ResPartnerRelationTypeSelection
from . import get_partner_type, PADDING
class ResPartnerRelationAll(Model):
class ResPartnerRelationAll(models.AbstractModel):
_auto = False
_log_access = False
_name = 'res.partner.relation.all'
_overlays = 'res.partner.relation'
_description = 'All (non-inverse + inverse) relations between partners'
_additional_view_fields = []
'''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:
Don't overwrite this list in your declaration but append in _auto_init:
def _auto_init(self, cr, context=None):
self._additional_view_fields.append('my_field')
@ -53,61 +55,82 @@ class ResPartnerRelationAll(Model):
additional_view_fields = (',' + additional_view_fields)\
if additional_view_fields else ''
cr.execute(
'''create or replace view %s as
'''create or replace view %(table)s as
select
id * 10 as id,
id * %(padding)d as id,
id as relation_id,
type_id,
cast('a' as char(1)) as record_type,
left_contact_type as contact_type,
left_partner_id as this_partner_id,
right_partner_id as other_partner_id,
date_start,
date_end,
active,
type_id * 10 as type_selection_id
%s
from res_partner_relation
type_id * %(padding)d as type_selection_id
%(additional_view_fields)s
from %(underlying_table)s
union select
id * 10 + 1,
id * %(padding)d + 1,
id,
type_id,
cast('b' as char(1)),
right_contact_type,
right_partner_id,
left_partner_id,
date_start,
date_end,
active,
type_id * 10 + 1
%s
from res_partner_relation''' % (
self._table,
additional_view_fields,
additional_view_fields,
)
type_id * %(padding)d + 1
%(additional_view_fields)s
from %(underlying_table)s''' % {
'table': self._table,
'padding': PADDING,
'additional_view_fields': additional_view_fields,
'underlying_table': 'res_partner_relation',
}
)
return super(ResPartnerRelationAll, self)._auto_init(
cr, context=context)
@api.one
def get_underlying_object(self):
"""Get the record on which this record is overlaid"""
return self.env[self._overlays].browse(self.id / PADDING)
contact_type = fields.Selection(
lambda s: s.env['res.partner.relation.type']._get_partner_types(),
'Partner Type',
default=lambda self: self._get_default_contact_type()
)
_columns = {
'record_type': fields.selection(
'record_type': osv.fields.selection(
ResPartnerRelationTypeSelection._RECORD_TYPES, 'Record type',
readonly=True),
'relation_id': fields.many2one(
'relation_id': osv.fields.many2one(
'res.partner.relation', 'Relation', readonly=True),
'type_id': fields.many2one(
'type_id': osv.fields.many2one(
'res.partner.relation.type', 'Relation type', readonly=True),
'type_selection_id': fields.many2one(
'type_selection_id': osv.fields.many2one(
'res.partner.relation.type.selection', 'Relation type',
readonly=True),
'this_partner_id': fields.many2one(
),
'this_partner_id': osv.fields.many2one(
'res.partner', 'Current partner', readonly=True),
'other_partner_id': fields.many2one(
'res.partner', 'Other partner', readonly=True),
'date_start': fields.date('Starting date'),
'date_end': fields.date('Ending date'),
'active': fields.boolean('Active'),
'other_partner_id': osv.fields.many2one(
'res.partner', 'Other partner'),
'date_start': osv.fields.date('Starting date'),
'date_end': osv.fields.date('Ending date'),
}
active = fields.Boolean('Active', default=True)
def _get_default_contact_type(self):
partner_id = self._context.get('default_this_partner_id')
if partner_id:
partner = self.env['res.partner'].browse(partner_id)
return get_partner_type(partner)
return False
def name_get(self, cr, uid, ids, context=None):
return dict([
@ -118,12 +141,40 @@ 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'''
return self.pool['res.partner.relation'].write(
cr, uid,
[i / 10 for i in ids],
dict([(k, vals[k])
for k in vals
if not self._columns[k].readonly]),
context=context)
@api.one
def write(self, vals):
"""divert non-problematic writes to underlying table"""
underlying_objs = self.get_underlying_object()
vals = {
key: val
for key, val in vals.iteritems()
if not self._columns[key].readonly
}
vals['type_selection_id'] = vals.get(
'type_selection_id',
underlying_objs.type_selection_id.id
)
return underlying_objs.write(vals)
@api.model
def create(self, vals):
"""divert non-problematic creates to underlying table
Create a res.partner.relation but return the converted id
"""
vals = {
key: val
for key, val in vals.iteritems()
if not self._columns[key].readonly
}
vals['type_selection_id'] = vals.get(
'type_selection_id',
False,
)
res = self.env[self._overlays].create(vals)
return self.browse(res.id * PADDING)
@api.one
def unlink(self):
"""divert non-problematic creates to underlying table"""
return self.get_underlying_object().unlink()

17
partner_relations/model/res_partner_relation_type.py

@ -19,18 +19,23 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv.orm import Model
from openerp.osv import fields
from openerp import models, api, _
class ResPartnerRelationType(Model):
'''Model that defines relation types that might exist between partners'''
class ResPartnerRelationType(models.Model):
"""Model that defines relation types that might exist between partners"""
_name = 'res.partner.relation.type'
_description = 'Parter relation type'
_description = 'Partner Relation Type'
_order = 'name'
def _get_partner_types(self, cr, uid, context=None):
return (('c', 'Company'), ('p', 'Person'),)
@api.model
def _get_partner_types(self):
return [
('c', _('Company')),
('p', _('Person')),
]
_columns = {
'name': fields.char(

37
partner_relations/model/res_partner_relation_type_selection.py

@ -27,11 +27,13 @@ ORDER BY ResPartnerRelationTypeSelection.customer_name asc,
ResPartnerRelationTypeSelection.caller_name asc;
'''
from openerp import api
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
from . import PADDING
class ResPartnerRelationTypeSelection(orm.Model):
@ -45,13 +47,14 @@ class ResPartnerRelationTypeSelection(orm.Model):
_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
@api.multi
def get_type_from_selection_id(self):
"""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.'''
type_id = selection_id / 10
is_reverse = (selection_id % 10) > 0
return (type_id, is_reverse)
back the original type id, and about the record type."""
type_id = self.id / PADDING
is_reverse = (self.id % PADDING) > 0
return type_id, is_reverse
def _auto_init(self, cr, context=None):
drop_view_if_exists(cr, self._table)
@ -59,9 +62,9 @@ class ResPartnerRelationTypeSelection(orm.Model):
# 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 %(table)s as
select
id * 10 as id,
id * %(padding)d as id,
id as type_id,
cast('a' as char(1)) as record_type,
name as name,
@ -69,9 +72,9 @@ class ResPartnerRelationTypeSelection(orm.Model):
contact_type_right as contact_type_other,
partner_category_left as partner_category_this,
partner_category_right as partner_category_other
from res_partner_relation_type
from %(underlying_table)s
union select
id * 10 + 1,
id * %(padding)d + 1,
id,
cast('b' as char(1)),
name_inverse,
@ -79,7 +82,11 @@ class ResPartnerRelationTypeSelection(orm.Model):
contact_type_left,
partner_category_right,
partner_category_left
from res_partner_relation_type''' % self._table)
from %(underlying_table)s''' % {
'table': self._table,
'padding': PADDING,
'underlying_table': 'res_partner_relation_type',
})
return super(ResPartnerRelationTypeSelection, self)._auto_init(
cr, context=context)
@ -161,8 +168,8 @@ class ResPartnerRelationTypeSelection(orm.Model):
cr, uid,
[
('id', 'in',
map(lambda x: x * 10, relation_ids) +
map(lambda x: x * 10 + 1, inverse_relation_ids)),
map(lambda x: x * PADDING, relation_ids) +
map(lambda x: x * PADDING + 1, inverse_relation_ids)),
] + (args or []),
context=context, limit=limit)
return self.name_get(cr, uid, all_ids, context=context)

2
partner_relations/view/res_partner.xml

@ -34,7 +34,7 @@
'active_ids': [id],
'active_test': False,
}"
name="%(action_res_partner_relation)d"
name="%(action_res_partner_relation_all)d"
icon="fa-users">
<field string="Relations" name="relation_count" widget="statinfo"/>
</button>

41
partner_relations/view/res_partner_relation.xml

@ -20,7 +20,7 @@
<field name="arch" type="xml">
<tree
string="Partner Relations"
colors="gray:is_relation_expired==True or not active;blue:is_relation_future==True"
colors="gray:date_end and date_end &lt; current_date or not active;blue:date_start &gt; current_date"
editable="bottom"
>
<field
@ -56,14 +56,6 @@
<field name="date_start" />
<field name="date_end" />
<field name="active" />
<field
name="is_relation_expired"
invisible="True"
/>
<field
name="is_relation_future"
invisible="True"
/>
</tree>
</field>
</record>
@ -86,36 +78,5 @@
<field name="value" eval="'ir.actions.server,%d' % ref('partner_relations.action_show_right_relation_partners')" />
</record>
<record id="search_res_partner_relation" model="ir.ui.view">
<field name="model">res.partner.relation</field>
<field name="arch" type="xml">
<search string="Search Relations">
<field name="left_partner_id"/>
<field name="right_partner_id"/>
<field name="type_id"/>
<group expand="0" string="Group By">
<filter string="Source Partner" context="{'group_by':'left_partner_id'}"/>
<filter string="Destination Partner" context="{'group_by':'right_partner_id'}"/>
<filter string="Relationship Type" context="{'group_by':'type_id'}"/>
</group>
</search>
</field>
</record>
<record id="action_res_partner_relation" model="ir.actions.act_window">
<field name="name">Relations</field>
<field name="res_model">res.partner.relation</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="tree_res_partner_relation"/>
<field name="search_view_id" ref="search_res_partner_relation"/>
<field name="context">{"search_default_left_partner_id": active_id}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely.
</p>
</field>
</record>
</data>
</openerp>

63
partner_relations/view/res_partner_relation_all.xml

@ -1,18 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="tree_res_partner_relation_all" model="ir.ui.view">
<field name="model">res.partner.relation.all</field>
<field name="arch" type="xml">
<tree string="Partner relations">
<field name="this_partner_id" />
<field name="type_selection_id" />
<field name="other_partner_id" />
<tree
string="Partner Relations"
colors="gray:(date_end and date_end &lt; current_date) or not active;blue:date_start &gt; current_date"
editable="bottom"
>
<field
name="this_partner_id"
readonly="1"
/>
<field
name="type_selection_id"
required="True"
domain="[
('contact_type_this', '=', contact_type),
]"
options="{'create': false, 'create_edit': false}"
/>
<field
name="other_partner_id"
attrs="{
'readonly': [('type_selection_id', '=', False)],
}"
options="{'create': false, 'create_edit': false}"
/>
<field name="date_start" />
<field name="date_end" />
<field name="active" />
<field name="contact_type" invisible="1"/>
</tree>
</field>
</record>
<record id="form_res_partner_relation_all" model="ir.ui.view">
<field name="model">res.partner.relation.all</field>
<field name="arch" type="xml">
@ -30,5 +54,36 @@
</form>
</field>
</record>
<record id="search_res_partner_relation_all" model="ir.ui.view">
<field name="model">res.partner.relation.all</field>
<field name="arch" type="xml">
<search string="Search Relations">
<field name="this_partner_id"/>
<field name="other_partner_id"/>
<field name="type_id"/>
<group expand="0" string="Group By">
<filter string="Other Partner" context="{'group_by': 'other_partner_id'}"/>
<filter string="Relationship Type" context="{'group_by': 'type_id'}"/>
</group>
</search>
</field>
</record>
<record id="action_res_partner_relation_all" model="ir.actions.act_window">
<field name="name">Relations</field>
<field name="res_model">res.partner.relation.all</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="tree_res_partner_relation_all"/>
<field name="search_view_id" ref="search_res_partner_relation_all"/>
<field name="context">{"search_default_this_partner_id": active_id}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Record and track your partners' relations. Relations may be linked to other partners with a type either directly or inversely.
</p>
</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save