You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
5.6 KiB

  1. # -*- coding: utf-8 -*-
  2. #
  3. #
  4. # Authors: Guewen Baconnier
  5. # Copyright 2015 Camptocamp SA
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as
  9. # published by the Free Software Foundation, either version 3 of the
  10. # License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. #
  21. from openerp import models, fields, api
  22. from openerp.tools.cache import ormcache
  23. class ChangesetFieldRule(models.Model):
  24. _name = 'changeset.field.rule'
  25. _description = 'Changeset Field Rules'
  26. _rec_name = 'field_id'
  27. field_id = fields.Many2one(
  28. comodel_name='ir.model.fields',
  29. string='Field',
  30. domain="[('model_id.model', '=', 'res.partner'), "
  31. " ('ttype', 'in', ('char', 'selection', 'date', 'datetime', "
  32. " 'float', 'integer', 'text', 'boolean', "
  33. " 'many2one')), "
  34. " ('readonly', '=', False)]",
  35. ondelete='cascade',
  36. required=True,
  37. )
  38. action = fields.Selection(
  39. selection='_selection_action',
  40. string='Action',
  41. required=True,
  42. help="Auto: always apply a change.\n"
  43. "Validate: manually applied by an administrator.\n"
  44. "Never: change never applied.",
  45. )
  46. source_model_id = fields.Many2one(
  47. comodel_name='ir.model',
  48. string='Source Model',
  49. ondelete='cascade',
  50. domain=lambda self: [('id', 'in', self._domain_source_models().ids)],
  51. help="If a source model is defined, the rule will be applied only "
  52. "when the change is made from this origin. "
  53. "Rules without source model are global and applies to all "
  54. "backends.\n"
  55. "Rules with a source model have precedence over global rules, "
  56. "but if a field has no rule with a source model, the global rule "
  57. "is used."
  58. )
  59. _sql_constraints = [
  60. ('model_field_uniq',
  61. 'unique (source_model_id, field_id)',
  62. 'A rule already exists for this field.'),
  63. ]
  64. @api.model
  65. def _domain_source_models(self):
  66. """ Returns the models for which we can define rules.
  67. Example for submodules (replace by the xmlid of the model):
  68. ::
  69. models = super(ChangesetFieldRule, self)._domain_source_models()
  70. return models | self.env.ref('base.model_res_users')
  71. Rules without model are global and apply for all models.
  72. """
  73. return self.env.ref('base.model_res_users')
  74. @api.model
  75. def _default_model_id(self):
  76. return self.env.ref('base.model_res_partner').id
  77. @api.model
  78. def _selection_action(self):
  79. return [('auto', 'Auto'),
  80. ('validate', 'Validate'),
  81. ('never', 'Never'),
  82. ]
  83. @ormcache()
  84. @api.model
  85. def _get_rules(self, model_name, source_model_name):
  86. """ Cache rules
  87. Keep only the id of the rules, because if we keep the recordsets
  88. in the ormcache, we won't be able to browse them once their
  89. cursor is closed.
  90. The public method ``get_rules`` return the rules with the recordsets
  91. when called.
  92. """
  93. model_rules = self.search(
  94. ['|', ('source_model_id.model', '=', source_model_name),
  95. ('source_model_id', '=', False)],
  96. # using 'ASC' means that 'NULLS LAST' is the default
  97. order='source_model_id ASC',
  98. )
  99. # model's rules have precedence over global ones so we iterate
  100. # over rules which have a source model first, then we complete
  101. # them with the global rules
  102. result = {}
  103. for rule in model_rules:
  104. # we already have a model's rule
  105. if result.get(rule.field_id.name):
  106. continue
  107. result[rule.field_id.name] = rule.id
  108. return result
  109. @api.model
  110. def get_rules(self, model_name, source_model_name):
  111. """ Return the rules for a model
  112. When a model is specified, it will return the rules for this
  113. model. Fields that have no rule for this model will use the
  114. global rules (those without source).
  115. The source model is the model which ask for a change, it will be
  116. for instance ``res.users``, ``lefac.backend`` or
  117. ``magellan.backend``.
  118. The second argument (``source_model_name``) is optional but
  119. cannot be an optional keyword argument otherwise it would not be
  120. in the key for the cache. The callers have to pass ``None`` if
  121. they want only global rules.
  122. """
  123. rules = {}
  124. cached_rules = self._get_rules(model_name, source_model_name)
  125. for field, rule_id in cached_rules.iteritems():
  126. rules[field] = self.browse(rule_id)
  127. return rules
  128. @api.model
  129. def create(self, vals):
  130. record = super(ChangesetFieldRule, self).create(vals)
  131. self.clear_caches()
  132. return record
  133. @api.multi
  134. def write(self, vals):
  135. result = super(ChangesetFieldRule, self).write(vals)
  136. self.clear_caches()
  137. return result
  138. @api.multi
  139. def unlink(self):
  140. result = super(ChangesetFieldRule, self).unlink()
  141. self.clear_caches()
  142. return result