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.

144 lines
4.9 KiB

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