#
##############################################################################
-from openerp.addons.base_status.base_stage import base_stage
-import binascii
+import openerp
from openerp.addons.crm import crm
from openerp.osv import fields, osv
-import time
from openerp import tools
from openerp.tools.translate import _
from openerp.tools import html2plaintext
-CRM_CLAIM_PENDING_STATES = (
- crm.AVAILABLE_STATES[2][0], # Cancelled
- crm.AVAILABLE_STATES[3][0], # Done
- crm.AVAILABLE_STATES[4][0], # Pending
-)
class crm_claim_stage(osv.osv):
""" Model for claim stages. This models the main stages of a claim
'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."),
'section_ids':fields.many2many('crm.case.section', 'section_claim_stage_rel', 'stage_id', 'section_id', string='Sections',
help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
- 'state': fields.selection(crm.AVAILABLE_STATES, 'Status', required=True, help="The related status for the stage. The status of your document will automatically change regarding the selected stage. For example, if a stage is related to the status 'Close', when your document reaches this stage, it will be automatically have the 'closed' status."),
- 'case_refused': fields.boolean('Refused stage',
- help='Refused stages are specific stages for done.'),
'case_default': fields.boolean('Common to All Teams',
help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."),
'fold': fields.boolean('Hide in Views when Empty',
_defaults = {
'sequence': lambda *args: 1,
- 'state': 'draft',
'fold': False,
- 'case_refused': False,
}
-class crm_claim(base_stage, osv.osv):
+class crm_claim(osv.osv):
""" Crm claim
"""
_name = "crm.claim"
_order = "priority,date desc"
_inherit = ['mail.thread']
+ def _get_default_section_id(self, cr, uid, context=None):
+ """ Gives default section by checking if present in the context """
+ return self.pool.get('crm.lead')._resolve_section_id_from_context(cr, uid, context=context) or False
+
+ def _get_default_stage_id(self, cr, uid, context=None):
+ """ Gives default stage_id """
+ section_id = self._get_default_section_id(cr, uid, context=context)
+ return self.stage_find(cr, uid, [], section_id, [('sequence', '=', '1')], context=context)
+
_columns = {
'id': fields.integer('ID', readonly=True),
'name': fields.char('Claim Subject', size=128, required=True),
'date_deadline': fields.date('Deadline'),
'date_closed': fields.datetime('Closed', readonly=True),
'date': fields.datetime('Claim Date', select=True),
- 'ref' : fields.reference('Reference', selection=crm._links_get, size=128),
+ 'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models),
'categ_id': fields.many2one('crm.case.categ', 'Category', \
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.claim')]"),
'email_from': fields.char('Email', size=128, help="Destination email for email gateway."),
'partner_phone': fields.char('Phone', size=32),
'stage_id': fields.many2one ('crm.claim.stage', 'Stage', track_visibility='onchange',
- domain="['&',('fold', '=', False),'|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
+ domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
'cause': fields.text('Root Cause'),
}
_defaults = {
- 'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
- 'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
- 'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
+ 'user_id': lambda s, cr, uid, c: uid,
'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
'date': fields.datetime.now,
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
'active': lambda *a: 1,
- 'stage_id':lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c)
+ 'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c)
}
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
return stage_ids[0]
return False
- def case_refuse(self, cr, uid, ids, context=None):
- """ Mark the case as refused: state=done and case_refused=True """
- for lead in self.browse(cr, uid, ids):
- stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, ['&', ('state', '=', 'done'), ('case_refused', '=', True)], context=context)
- if stage_id:
- self.case_set(cr, uid, [lead.id], values_to_update={}, new_stage_id=stage_id, context=context)
- return True
-
- def onchange_partner_id(self, cr, uid, ids, part, email=False):
+ def onchange_partner_id(self, cr, uid, ids, partner_id, email=False, context=None):
"""This function returns value of partner address based on partner
- :param part: Partner's id
:param email: ignored
"""
- if not part:
- return {'value': {'email_from': False,
- 'partner_phone': False
- }
- }
- address = self.pool.get('res.partner').browse(cr, uid, part)
+ if not partner_id:
+ return {'value': {'email_from': False, 'partner_phone': False}}
+ address = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
return {'value': {'email_from': address.email, 'partner_phone': address.phone}}
+ def create(self, cr, uid, vals, context=None):
+ if context is None:
+ context = {}
+ if vals.get('section_id') and not context.get('default_section_id'):
+ context['default_section_id'] = vals.get('section_id')
+
+ # context: no_log, because subtype already handle this
+ return super(crm_claim, self).create(cr, uid, vals, context=context)
+
+ def copy(self, cr, uid, id, default=None, context=None):
+ claim = self.browse(cr, uid, id, context=context)
+ default = dict(default or {},
+ stage_id = self._get_default_stage_id(cr, uid, context=context),
+ name = _('%s (copy)') % claim.name)
+ return super(crm_claim, self).copy(cr, uid, id, default, context=context)
+
# -------------------------------------------------------
# Mail gateway
# -------------------------------------------------------
from openerp.osv.orm import MAGIC_COLUMNS
import openerp.tools as tools
-#.apidoc title: Domain Expressions
# Domain operators.
NOT_OPERATOR = '!'
field_path = left.split('.', 1)
field = working_model._columns.get(field_path[0])
if field and field._obj:
- relational_model = working_model.pool.get(field._obj)
+ relational_model = working_model.pool[field._obj]
else:
relational_model = None
# comments about inherits'd fields
# { 'field_name': ('parent_model', 'm2o_field_to_reach_parent',
# field_column_obj, origina_parent_model), ... }
- next_model = working_model.pool.get(working_model._inherit_fields[field_path[0]][0])
+ next_model = working_model.pool[working_model._inherit_fields[field_path[0]][0]]
leaf.add_join_context(next_model, working_model._inherits[next_model._name], 'id', working_model._inherits[next_model._name])
push(leaf)
else:
if field._type == 'datetime' and right and len(right) == 10:
- if operator in ('>', '>='):
- right += ' 00:00:00'
- elif operator in ('<', '<='):
+ if operator in ('>', '<='):
right += ' 23:59:59'
+ else:
+ right += ' 00:00:00'
push(create_substitution_leaf(leaf, (left, operator, right), working_model))
elif field.translate and right:
unaccent = self._unaccent if sql_operator.endswith('like') else lambda x: x
- trans_left = unaccent('value')
- quote_left = unaccent(_quote(left))
instr = unaccent('%s')
if sql_operator == 'in':
# params will be flatten by to_sql() => expand the placeholders
instr = '(%s)' % ', '.join(['%s'] * len(right))
- subselect = """(SELECT res_id
- FROM ir_translation
- WHERE name = %s
- AND lang = %s
- AND type = %s
- AND {trans_left} {operator} {right}
- ) UNION (
- SELECT id
- FROM "{table}"
- WHERE {left} {operator} {right}
- )
- """.format(trans_left=trans_left, operator=sql_operator,
- right=instr, table=working_model._table, left=quote_left)
+ subselect = """WITH temp_irt_current (id, name) as (
+ SELECT ct.id, coalesce(it.value,ct.{quote_left})
+ FROM {current_table} ct
+ LEFT JOIN ir_translation it ON (it.name = %s and
+ it.lang = %s and
+ it.type = %s and
+ it.res_id = ct.id and
+ it.value != '')
+ )
+ SELECT id FROM temp_irt_current WHERE {name} {operator} {right} order by name
+ """.format(current_table=working_model._table, quote_left=_quote(left), name=unaccent('name'),
+ operator=sql_operator, right=instr)
params = (
working_model._name + ',' + left,
context.get('lang') or 'en_US',
'model',
right,
- right,
)
push(create_substitution_leaf(leaf, ('id', inselect_operator, (subselect, params)), working_model))
if left == 'id':
instr = ','.join(['%s'] * len(params))
else:
- instr = ','.join([model._columns[left]._symbol_set[0]] * len(params))
+ ss = model._columns[left]._symbol_set
+ instr = ','.join([ss[0]] * len(params))
+ params = map(ss[1], params)
query = '(%s."%s" %s (%s))' % (table_alias, left, operator, instr)
else:
# The case for (left, 'in', []) or (left, 'not in', []).
import base64
import datetime as DT
+import functools
import logging
import pytz
import re
self._context = context
self.write = False
self.read = False
- self.view_load = 0
self.select = select
self.manual = manual
self.selectable = True
_type = 'reference'
_classic_read = False # post-process to handle missing target
- def __init__(self, string, selection, size, **args):
+ def __init__(self, string, selection, size=None, **args):
_column.__init__(self, string=string, size=size, selection=selection, **args)
def get(self, cr, obj, ids, name, uid=None, context=None, values=None):
result[value['id']] = value[name]
if value[name]:
model, res_id = value[name].split(',')
- if not obj.pool.get(model).exists(cr, uid, [int(res_id)], context=context):
+ if not obj.pool[model].exists(cr, uid, [int(res_id)], context=context):
result[value['id']] = False
return result
# reference fields have a 'model,id'-like value, that we need to convert
# to a real name
model_name, res_id = value.split(',')
- model = obj.pool.get(model_name)
- if model and res_id:
+ if model_name in obj.pool and res_id:
+ model = obj.pool[model_name]
names = model.name_get(cr, uid, [int(res_id)], context=context)
return names[0][1] if names else False
return tools.ustr(value)
class text(_column):
_type = 'text'
+
class html(text):
_type = 'html'
_symbol_c = '%s'
- def _symbol_f(x):
- if x is None or x == False:
+
+ def _symbol_set_html(self, value):
+ if value is None or value is False:
return None
- return html_sanitize(x)
-
- _symbol_set = (_symbol_c, _symbol_f)
+ if not self._sanitize:
+ return value
+ return html_sanitize(value)
+
+ def __init__(self, string='unknown', sanitize=True, **args):
+ super(html, self).__init__(string=string, **args)
+ self._sanitize = sanitize
+ # symbol_set redefinition because of sanitize specific behavior
+ self._symbol_f = self._symbol_set_html
+ self._symbol_set = (self._symbol_c, self._symbol_f)
import __builtin__
class date(_column):
_type = 'date'
+ MONTHS = [
+ ('01', 'January'),
+ ('02', 'February'),
+ ('03', 'March'),
+ ('04', 'April'),
+ ('05', 'May'),
+ ('06', 'June'),
+ ('07', 'July'),
+ ('08', 'August'),
+ ('09', 'September'),
+ ('10', 'October'),
+ ('11', 'November'),
+ ('12', 'December')
+ ]
+
@staticmethod
def today(*args):
""" Returns the current date in a format fit for being a
class datetime(_column):
_type = 'datetime'
+
+ MONTHS = [
+ ('01', 'January'),
+ ('02', 'February'),
+ ('03', 'March'),
+ ('04', 'April'),
+ ('05', 'May'),
+ ('06', 'June'),
+ ('07', 'July'),
+ ('08', 'August'),
+ ('09', 'September'),
+ ('10', 'October'),
+ ('11', 'November'),
+ ('12', 'December')
+ ]
+
@staticmethod
def now(*args):
""" Returns the current datetime in a format fit for being a
_column.__init__(self, string=string, **args)
self.selection = selection
+ @classmethod
+ def reify(cls, cr, uid, model, field, context=None):
+ """ Munges the field's ``selection`` attribute as necessary to get
+ something useable out of it: calls it if it's a function, applies
+ translations to labels if it's not.
+
+ A callable ``selection`` is considered translated on its own.
+
+ :param orm.Model model:
+ :param _column field:
+ """
+ if callable(field.selection):
+ return field.selection(model, cr, uid, context)
+
+ if not (context and 'lang' in context):
+ return field.selection
+
+ # field_to_dict isn't given a field name, only a field object, we
+ # need to get the name back in order to perform the translation lookup
+ field_name = next(
+ name for name, column in model._columns.iteritems()
+ if column == field)
+
+ translation_filter = "%s,%s" % (model._name, field_name)
+ translate = functools.partial(
+ model.pool['ir.translation']._get_source,
+ cr, uid, translation_filter, 'selection', context['lang'])
+
+ return [
+ (value, translate(label))
+ for value, label in field.selection
+ ]
+
# ---------------------------------------------------------
# Relationals fields
# ---------------------------------------------------------
res[r['id']] = r[name]
for id in ids:
res.setdefault(id, '')
- obj = obj.pool.get(self._obj)
+ obj = obj.pool[self._obj]
# build a dictionary of the form {'id_of_distant_resource': name_of_distant_resource}
# we use uid=1 because the visibility of a many2one field value (just id and name)
def set(self, cr, obj_src, id, field, values, user=None, context=None):
if not context:
context = {}
- obj = obj_src.pool.get(self._obj)
- self._table = obj_src.pool.get(self._obj)._table
+ obj = obj_src.pool[self._obj]
+ self._table = obj._table
if type(values) == type([]):
for act in values:
if act[0] == 0:
cr.execute('update '+obj_src._table+' set '+field+'=null where id=%s', (id,))
def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, context=None):
- return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name', 'like', value)], offset, limit, context=context)
+ return obj.pool[self._obj].search(cr, uid, args+self._domain+[('name', 'like', value)], offset, limit, context=context)
@classmethod
res[id] = []
domain = self._domain(obj) if callable(self._domain) else self._domain
- ids2 = obj.pool.get(self._obj).search(cr, user, domain + [(self._fields_id, 'in', ids)], limit=self._limit, context=context)
- for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
- if r[self._fields_id] in res:
- res[r[self._fields_id]].append(r['id'])
+ model = obj.pool[self._obj]
+ ids2 = model.search(cr, user, domain + [(self._fields_id, 'in', ids)], limit=self._limit, context=context)
+ if len(ids) != 1:
+ for r in model._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
+ if r[self._fields_id] in res:
+ res[r[self._fields_id]].append(r['id'])
+ else:
+ res[ids[0]] = ids2
return res
def set(self, cr, obj, id, field, values, user=None, context=None):
context['no_store_function'] = True
if not values:
return
- _table = obj.pool.get(self._obj)._table
- obj = obj.pool.get(self._obj)
+ obj = obj.pool[self._obj]
+ _table = obj._table
for act in values:
if act[0] == 0:
act[2][self._fields_id] = id
def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None):
domain = self._domain(obj) if callable(self._domain) else self._domain
- return obj.pool.get(self._obj).name_search(cr, uid, value, domain, operator, context=context,limit=limit)
+ return obj.pool[self._obj].name_search(cr, uid, value, domain, operator, context=context,limit=limit)
@classmethod
tbl, col1, col2 = self._rel, self._id1, self._id2
if not all((tbl, col1, col2)):
# the default table name is based on the stable alphabetical order of tables
- dest_model = source_model.pool.get(self._obj)
+ dest_model = source_model.pool[self._obj]
tables = tuple(sorted([source_model._table, dest_model._table]))
if not tbl:
assert tables[0] != tables[1], 'Implicit/Canonical naming of m2m relationship table '\
_logger.warning(
"Specifying offset at a many2many.get() is deprecated and may"
" produce unpredictable results.")
- obj = model.pool.get(self._obj)
+ obj = model.pool[self._obj]
rel, id1, id2 = self._sql_names(model)
# static domains are lists, and are evaluated both here and on client-side, while string
if not values:
return
rel, id1, id2 = self._sql_names(model)
- obj = model.pool.get(self._obj)
+ obj = model.pool[self._obj]
for act in values:
if not (isinstance(act, list) or isinstance(act, tuple)) or not act:
continue
# TODO: use a name_search
#
def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None):
- return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name', operator, value)], offset, limit, context=context)
+ return obj.pool[self._obj].search(cr, uid, args+self._domain+[('name', operator, value)], offset, limit, context=context)
@classmethod
def _as_display_name(cls, field, cr, uid, obj, value, context=None):
if field_type == "many2one":
# make the result a tuple if it is not already one
if isinstance(value, (int,long)) and hasattr(obj._columns[field], 'relation'):
- obj_model = obj.pool.get(obj._columns[field].relation)
+ obj_model = obj.pool[obj._columns[field].relation]
dict_names = dict(obj_model.name_get(cr, SUPERUSER_ID, [value], context))
result = (value, dict_names[value])
# Perform name_get as root, as seeing the name of a related object depends on
# access right of source document, not target, so user may not have access.
value_ids = list(set(value.id for value in res.itervalues() if value))
- value_name = dict(obj.pool.get(self._obj).name_get(cr, SUPERUSER_ID, value_ids, context=context))
+ value_name = dict(obj.pool[self._obj].name_get(cr, SUPERUSER_ID, value_ids, context=context))
res = dict((id, value and (value.id, value_name[value.id])) for id, value in res.iteritems())
elif self._type in ('one2many', 'many2many'):
elif self._type == 'one2many':
if not read_value:
read_value = []
- relation_obj = obj.pool.get(self.relation)
+ relation_obj = obj.pool[self.relation]
for vals in value:
assert vals[0] in (0,1,2), 'Unsupported o2m value for sparse field: %s' % vals
if vals[0] == 0:
value = value or []
if value:
# filter out deleted records as superuser
- relation_obj = obj.pool.get(obj._columns[field_name].relation)
+ relation_obj = obj.pool[obj._columns[field_name].relation]
value = relation_obj.exists(cr, openerp.SUPERUSER_ID, value)
if type(value) in (int,long) and field_type == 'many2one':
- relation_obj = obj.pool.get(obj._columns[field_name].relation)
+ relation_obj = obj.pool[obj._columns[field_name].relation]
# check for deleted record as superuser
if not relation_obj.exists(cr, openerp.SUPERUSER_ID, [value]):
value = False
def __init__(self, *arg, **args):
self.arg = arg
self._relations = []
- super(dummy, self).__init__(self._fnct_read, arg, self._fnct_write, fnct_inv_arg=arg, fnct_search=None, **args)
+ super(dummy, self).__init__(self._fnct_read, arg, self._fnct_write, fnct_inv_arg=arg, fnct_search=self._fnct_search, **args)
# ---------------------------------------------------------
# Serialized fields
default_val = self._get_default(obj, cr, uid, prop_name, context)
property_create = False
- if isinstance(default_val, openerp.osv.orm.browse_record):
+ if isinstance(default_val, (openerp.osv.orm.browse_record,
+ openerp.osv.orm.browse_null)):
if default_val.id != id_val:
property_create = True
elif default_val != id_val:
# not target, so user may not have access) in order to avoid
# pointing on an unexisting record.
if property_destination_obj:
- if res[id][prop_name] and obj.pool.get(property_destination_obj).exists(cr, SUPERUSER_ID, res[id][prop_name].id):
+ if res[id][prop_name] and obj.pool[property_destination_obj].exists(cr, SUPERUSER_ID, res[id][prop_name].id):
name_get_ids[id] = res[id][prop_name].id
else:
res[id][prop_name] = False
# name_get as root (as seeing the name of a related
# object depends on access right of source document,
# not target, so user may not have access.)
- name_get_values = dict(obj.pool.get(property_destination_obj).name_get(cr, SUPERUSER_ID, name_get_ids.values(), context=context))
+ name_get_values = dict(obj.pool[property_destination_obj].name_get(cr, SUPERUSER_ID, name_get_ids.values(), context=context))
# the property field is a m2o, we need to return a tuple with (id, name)
for k, v in name_get_ids.iteritems():
if res[k][prop_name]:
self.field_id[cr.dbname] = res and res[0]
return self.field_id[cr.dbname]
- def __init__(self, obj_prop, **args):
- # TODO remove obj_prop parameter (use many2one type)
+
+ def __init__(self, **args):
self.field_id = {}
- function.__init__(self, self._fnct_read, False, self._fnct_write,
- obj_prop, multi='properties', **args)
+ if 'view_load' in args:
+ _logger.warning("view_load attribute is deprecated on ir.fields. Args: %r", args)
+ obj = 'relation' in args and args['relation'] or ''
+ function.__init__(self, self._fnct_read, False, self._fnct_write, obj=obj, multi='properties', **args)
def restart(self):
self.field_id = {}
res[arg] = getattr(field, arg)
if hasattr(field, 'selection'):
- if isinstance(field.selection, (tuple, list)):
- res['selection'] = field.selection
- else:
- # call the 'dynamic selection' function
- res['selection'] = field.selection(model, cr, user, context)
+ res['selection'] = selection.reify(cr, user, model, field, context=context)
if res['type'] in ('one2many', 'many2many', 'many2one'):
res['relation'] = field._obj
res['domain'] = field._domain(model) if callable(field._domain) else field._domain