1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from odoo import api, fields, models, tools, _
from odoo.exceptions import ValidationError
class IrDefault(models.Model):
""" User-defined default values for fields. """
_name = 'ir.default'
_rec_name = 'field_id'
field_id = fields.Many2one('ir.model.fields', string="Field", required=True,
ondelete='cascade', index=True)
user_id = fields.Many2one('res.users', string='User', ondelete='cascade', index=True,
help="If set, action binding only applies for this user.")
company_id = fields.Many2one('res.company', string='Company', ondelete='cascade', index=True,
help="If set, action binding only applies for this company")
condition = fields.Char('Condition', help="If set, applies the default upon condition.")
json_value = fields.Char('Default Value (JSON format)', required=True)
@api.model
def create(self, vals):
self.clear_caches()
return super(IrDefault, self).create(vals)
@api.multi
def write(self, vals):
if self:
self.clear_caches()
return super(IrDefault, self).write(vals)
@api.multi
def unlink(self):
if self:
self.clear_caches()
return super(IrDefault, self).unlink()
@api.model
def set(self, model_name, field_name, value, user_id=False, company_id=False, condition=False):
""" Defines a default value for the given field. Any entry for the same
scope (field, user, company) will be replaced. The value is encoded
in JSON to be stored to the database.
:param user_id: may be ``False`` for all users, ``True`` for the
current user, or any user id
:param company_id: may be ``False`` for all companies, ``True`` for
the current user's company, or any company id
:param condition: optional condition that restricts the
applicability of the default value; this is an
opaque string, but the client typically uses
single-field conditions in the form ``'key=val'``.
"""
if user_id is True:
user_id = self.env.uid
if company_id is True:
company_id = self.env.user.company_id.id
# check consistency of model_name, field_name, and value
try:
model = self.env[model_name]
field = model._fields[field_name]
field.convert_to_cache(value, model)
json_value = json.dumps(value, ensure_ascii=False)
except KeyError:
raise ValidationError(_("Invalid field %s.%s") % (model_name, field_name))
except Exception:
raise ValidationError(_("Invalid value for %s.%s: %s") % (model_name, field_name, value))
# update existing default for the same scope, or create one
field = self.env['ir.model.fields']._get(model_name, field_name)
default = self.search([
('field_id', '=', field.id),
('user_id', '=', user_id),
('company_id', '=', company_id),
('condition', '=', condition),
])
if default:
default.write({'json_value': json_value})
else:
self.create({
'field_id': field.id,
'user_id': user_id,
'company_id': company_id,
'condition': condition,
'json_value': json_value,
})
return True
@api.model
def get(self, model_name, field_name, user_id=False, company_id=False, condition=False):
""" Return the default value for the given field, user and company, or
``None`` if no default is available.
:param user_id: may be ``False`` for all users, ``True`` for the
current user, or any user id
:param company_id: may be ``False`` for all companies, ``True`` for
the current user's company, or any company id
:param condition: optional condition that restricts the
applicability of the default value; this is an
opaque string, but the client typically uses
single-field conditions in the form ``'key=val'``.
"""
if user_id is True:
user_id = self.env.uid
if company_id is True:
company_id = self.env.user.company_id.id
field = self.env['ir.model.fields']._get(model_name, field_name)
default = self.search([
('field_id', '=', field.id),
('user_id', '=', user_id),
('company_id', '=', company_id),
('condition', '=', condition),
], limit=1)
return json.loads(default.json_value) if default else None
@api.model
@tools.ormcache('self.env.uid', 'model_name', 'condition')
# Note about ormcache invalidation: it is not needed when deleting a field,
# a user, or a company, as the corresponding defaults will no longer be
# requested. It must only be done when a user's company is modified.
def get_model_defaults(self, model_name, condition=False):
""" Return the available default values for the given model (for the
current user), as a dict mapping field names to values.
"""
cr = self.env.cr
query = """ SELECT f.name, d.json_value FROM ir_default d
JOIN ir_model_fields f ON d.field_id=f.id
JOIN res_users u ON u.id=%s
WHERE f.model=%s
AND (d.user_id IS NULL OR d.user_id=u.id)
AND (d.company_id IS NULL OR d.company_id=u.company_id)
AND {}
ORDER BY d.user_id, d.company_id, d.id
"""
params = [self.env.uid, model_name]
if condition:
query = query.format("d.condition=%s")
params.append(condition)
else:
query = query.format("d.condition IS NULL")
cr.execute(query, params)
result = {}
for row in cr.fetchall():
# keep the highest priority default for each field
if row[0] not in result:
result[row[0]] = json.loads(row[1])
return result
@api.model
def discard_records(self, records):
""" Discard all the defaults of many2one fields using any of the given
records.
"""
json_vals = [json.dumps(id) for id in records.ids]
domain = [('field_id.ttype', '=', 'many2one'),
('field_id.relation', '=', records._name),
('json_value', 'in', json_vals)]
return self.search(domain).unlink()
@api.model
def discard_values(self, model_name, field_name, values):
""" Discard all the defaults for any of the given values. """
field = self.env['ir.model.fields']._get(model_name, field_name)
json_vals = [json.dumps(value, ensure_ascii=False) for value in values]
domain = [('field_id', '=', field.id), ('json_value', 'in', json_vals)]
return self.search(domain).unlink()
|