239 lines
8.9 KiB
Python
239 lines
8.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
##############################################################################
|
|
#
|
|
# OpenERP, Open Source Management Solution
|
|
# Copyright (C) 2013-2014 OpenERP (<http://www.openerp.com>).
|
|
#
|
|
# 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/>.
|
|
#
|
|
##############################################################################
|
|
|
|
import datetime
|
|
from openerp.exceptions import AccessError
|
|
|
|
##############################################################################
|
|
#
|
|
# OLD API
|
|
#
|
|
##############################################################################
|
|
from openerp.osv import osv, fields
|
|
|
|
|
|
class res_partner(osv.Model):
|
|
_inherit = 'res.partner'
|
|
|
|
#
|
|
# add related fields to test them
|
|
#
|
|
_columns = {
|
|
# a regular one
|
|
'related_company_partner_id': fields.related(
|
|
'company_id', 'partner_id', type='many2one', obj='res.partner'),
|
|
# a related field with a single field
|
|
'single_related_company_id': fields.related(
|
|
'company_id', type='many2one', obj='res.company'),
|
|
# a related field with a single field that is also a related field!
|
|
'related_related_company_id': fields.related(
|
|
'single_related_company_id', type='many2one', obj='res.company'),
|
|
}
|
|
|
|
|
|
class TestFunctionCounter(osv.Model):
|
|
_name = 'test_old_api.function_counter'
|
|
|
|
def _compute_cnt(self, cr, uid, ids, fname, arg, context=None):
|
|
res = {}
|
|
for cnt in self.browse(cr, uid, ids, context=context):
|
|
res[cnt.id] = cnt.access and cnt.cnt + 1 or 0
|
|
return res
|
|
|
|
_columns = {
|
|
'access': fields.datetime('Datetime Field'),
|
|
'cnt': fields.function(
|
|
_compute_cnt, type='integer', string='Function Field', store=True),
|
|
}
|
|
|
|
|
|
class TestFunctionNoInfiniteRecursion(osv.Model):
|
|
_name = 'test_old_api.function_noinfiniterecursion'
|
|
|
|
def _compute_f1(self, cr, uid, ids, fname, arg, context=None):
|
|
res = {}
|
|
for tf in self.browse(cr, uid, ids, context=context):
|
|
res[tf.id] = 'create' in tf.f0 and 'create' or 'write'
|
|
cntobj = self.pool['test_old_api.function_counter']
|
|
cnt_id = self.pool['ir.model.data'].xmlid_to_res_id(
|
|
cr, uid, 'test_new_api.c1')
|
|
cntobj.write(
|
|
cr, uid, cnt_id, {'access': datetime.datetime.now()},
|
|
context=context)
|
|
return res
|
|
|
|
_columns = {
|
|
'f0': fields.char('Char Field'),
|
|
'f1': fields.function(
|
|
_compute_f1, type='char', string='Function Field', store=True),
|
|
}
|
|
|
|
##############################################################################
|
|
#
|
|
# NEW API
|
|
#
|
|
##############################################################################
|
|
from openerp import models, fields, api, _
|
|
|
|
|
|
class Category(models.Model):
|
|
_name = 'test_new_api.category'
|
|
|
|
name = fields.Char(required=True)
|
|
parent = fields.Many2one('test_new_api.category')
|
|
display_name = fields.Char(compute='_compute_display_name', inverse='_inverse_display_name')
|
|
discussions = fields.Many2many('test_new_api.discussion', 'test_new_api_discussion_category',
|
|
'category', 'discussion')
|
|
|
|
@api.one
|
|
@api.depends('name', 'parent.display_name') # this definition is recursive
|
|
def _compute_display_name(self):
|
|
if self.parent:
|
|
self.display_name = self.parent.display_name + ' / ' + self.name
|
|
else:
|
|
self.display_name = self.name
|
|
|
|
@api.one
|
|
def _inverse_display_name(self):
|
|
names = self.display_name.split('/')
|
|
# determine sequence of categories
|
|
categories = []
|
|
for name in names[:-1]:
|
|
category = self.search([('name', 'ilike', name.strip())])
|
|
categories.append(category[0])
|
|
categories.append(self)
|
|
# assign parents following sequence
|
|
for parent, child in zip(categories, categories[1:]):
|
|
if parent and child:
|
|
child.parent = parent
|
|
# assign name of last category, and reassign display_name (to normalize it)
|
|
self.name = names[-1].strip()
|
|
|
|
def read(self, fields=None, load='_classic_read'):
|
|
if self.search_count([('id', 'in', self._ids), ('name', '=', 'NOACCESS')]):
|
|
raise AccessError('Sorry')
|
|
return super(Category, self).read(fields, load)
|
|
|
|
class Discussion(models.Model):
|
|
_name = 'test_new_api.discussion'
|
|
|
|
name = fields.Char(string='Title', required=True,
|
|
help="General description of what this discussion is about.")
|
|
moderator = fields.Many2one('res.users')
|
|
categories = fields.Many2many('test_new_api.category',
|
|
'test_new_api_discussion_category', 'discussion', 'category')
|
|
participants = fields.Many2many('res.users')
|
|
messages = fields.One2many('test_new_api.message', 'discussion')
|
|
message_changes = fields.Integer(string='Message changes')
|
|
|
|
@api.onchange('moderator')
|
|
def _onchange_moderator(self):
|
|
self.participants |= self.moderator
|
|
|
|
@api.onchange('messages')
|
|
def _onchange_messages(self):
|
|
self.message_changes = len(self.messages)
|
|
|
|
|
|
class Message(models.Model):
|
|
_name = 'test_new_api.message'
|
|
|
|
discussion = fields.Many2one('test_new_api.discussion', ondelete='cascade')
|
|
body = fields.Text()
|
|
author = fields.Many2one('res.users', default=lambda self: self.env.user)
|
|
name = fields.Char(string='Title', compute='_compute_name', store=True)
|
|
display_name = fields.Char(string='Abstract', compute='_compute_display_name')
|
|
size = fields.Integer(compute='_compute_size', search='_search_size')
|
|
double_size = fields.Integer(compute='_compute_double_size')
|
|
discussion_name = fields.Char(related='discussion.name')
|
|
|
|
@api.one
|
|
@api.constrains('author', 'discussion')
|
|
def _check_author(self):
|
|
if self.discussion and self.author not in self.discussion.participants:
|
|
raise ValueError(_("Author must be among the discussion participants."))
|
|
|
|
@api.one
|
|
@api.depends('author.name', 'discussion.name')
|
|
def _compute_name(self):
|
|
self.name = "[%s] %s" % (self.discussion.name or '', self.author.name or '')
|
|
|
|
@api.one
|
|
@api.depends('author.name', 'discussion.name', 'body')
|
|
def _compute_display_name(self):
|
|
stuff = "[%s] %s: %s" % (self.author.name, self.discussion.name or '', self.body or '')
|
|
self.display_name = stuff[:80]
|
|
|
|
@api.one
|
|
@api.depends('body')
|
|
def _compute_size(self):
|
|
self.size = len(self.body or '')
|
|
|
|
def _search_size(self, operator, value):
|
|
if operator not in ('=', '!=', '<', '<=', '>', '>=', 'in', 'not in'):
|
|
return []
|
|
# retrieve all the messages that match with a specific SQL query
|
|
query = """SELECT id FROM "%s" WHERE char_length("body") %s %%s""" % \
|
|
(self._table, operator)
|
|
self.env.cr.execute(query, (value,))
|
|
ids = [t[0] for t in self.env.cr.fetchall()]
|
|
return [('id', 'in', ids)]
|
|
|
|
@api.one
|
|
@api.depends('size')
|
|
def _compute_double_size(self):
|
|
# This illustrates a subtle situation: self.double_size depends on
|
|
# self.size. When size is computed, self.size is assigned, which should
|
|
# normally invalidate self.double_size. However, this may not happen
|
|
# while self.double_size is being computed: the last statement below
|
|
# would fail, because self.double_size would be undefined.
|
|
self.double_size = 0
|
|
size = self.size
|
|
self.double_size = self.double_size + size
|
|
|
|
|
|
class MixedModel(models.Model):
|
|
_name = 'test_new_api.mixed'
|
|
|
|
number = fields.Float(digits=(10, 2), default=3.14)
|
|
date = fields.Date()
|
|
now = fields.Datetime(compute='_compute_now')
|
|
lang = fields.Selection(string='Language', selection='_get_lang')
|
|
reference = fields.Reference(string='Related Document',
|
|
selection='_reference_models')
|
|
|
|
@api.one
|
|
def _compute_now(self):
|
|
# this is a non-stored computed field without dependencies
|
|
self.now = fields.Datetime.now()
|
|
|
|
@api.model
|
|
def _get_lang(self):
|
|
langs = self.env['res.lang'].search([])
|
|
return [(lang.code, lang.name) for lang in langs]
|
|
|
|
@api.model
|
|
def _reference_models(self):
|
|
models = self.env['ir.model'].search([('state', '!=', 'manual')])
|
|
return [(model.model, model.name)
|
|
for model in models
|
|
if not model.model.startswith('ir.')]
|