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.

127 lines
4.7 KiB

  1. ###################################################################################
  2. #
  3. # Copyright (C) 2017 MuK IT GmbH
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU Affero General Public License as
  7. # published by the Free Software Foundation, either version 3 of the
  8. # License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Affero General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. #
  18. ###################################################################################
  19. import json
  20. import operator
  21. import functools
  22. import collections
  23. from odoo import models, fields, api
  24. class Hierarchy(models.AbstractModel):
  25. _name = 'muk_utils.mixins.hierarchy'
  26. _description = 'Hierarchy Mixin'
  27. _parent_store = True
  28. _parent_path_sudo = False
  29. _parent_path_store = False
  30. #----------------------------------------------------------
  31. # Database
  32. #----------------------------------------------------------
  33. parent_path = fields.Char(
  34. string="Parent Path",
  35. index=True)
  36. @api.model
  37. def _add_magic_fields(self):
  38. super(Hierarchy, self)._add_magic_fields()
  39. def add(name, field):
  40. if name not in self._fields:
  41. self._add_field(name, field)
  42. path_names_search = None
  43. if not self._parent_path_store:
  44. path_names_search = '_search_parent_path_names',
  45. add('parent_path_names', fields.Char(
  46. _module=self._module,
  47. compute='_compute_parent_path',
  48. compute_sudo=self._parent_path_sudo,
  49. store=self._parent_path_store,
  50. search=path_names_search,
  51. string="Path Names",
  52. readonly=True,
  53. automatic=True))
  54. add('parent_path_json', fields.Text(
  55. _module=self._module,
  56. compute='_compute_parent_path',
  57. compute_sudo=self._parent_path_sudo,
  58. store=self._parent_path_store,
  59. string="Path Json",
  60. readonly=True,
  61. automatic=True))
  62. #----------------------------------------------------------
  63. # Search
  64. #----------------------------------------------------------
  65. @api.model
  66. def _search_parent_path_names(self, operator, operand):
  67. domain = []
  68. for value in operand.split('/'):
  69. args = [(self._rec_name_fallback(), operator, value)]
  70. domain = expression.OR(args, domain) if domain else args
  71. return domain
  72. #----------------------------------------------------------
  73. # Read, View
  74. #----------------------------------------------------------
  75. @api.depends('parent_path')
  76. def _compute_parent_path(self):
  77. records = self.filtered(lambda record: record.parent_path)
  78. paths = [list(map(int, rec.parent_path.split('/')[:-1])) for rec in records]
  79. ids = paths and set(functools.reduce(operator.concat, paths)) or []
  80. data = dict(self.browse(ids)._filter_access('read').name_get())
  81. for record in records:
  82. path_names = [""]
  83. path_json = []
  84. for id in reversed(list(map(int, record.parent_path.split('/')[:-1]))):
  85. if id not in data:
  86. break
  87. path_names.append(data[id])
  88. path_json.append({
  89. 'model': record._name,
  90. 'name': data[id],
  91. 'id': id,
  92. })
  93. path_names.reverse()
  94. path_json.reverse()
  95. record.update({
  96. 'parent_path_names': '/'.join(path_names),
  97. 'parent_path_json': json.dumps(path_json),
  98. })
  99. #----------------------------------------------------------
  100. # Create, Update, Delete
  101. #----------------------------------------------------------
  102. @api.multi
  103. def write(self, vals):
  104. if self._parent_path_store and self._rec_name_fallback() in vals:
  105. with self.env.norecompute():
  106. res = super(Hierarchy, self).write(vals)
  107. domain = [('id', 'child_of', self.ids)]
  108. records = self.sudo().search(domain)
  109. records.modified(['parent_path'])
  110. if self.env.recompute and self.env.context.get('recompute', True):
  111. records.recompute()
  112. return res
  113. return super(Hierarchy, self).write(vals)