ir_default.py 7.9 KB

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