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.

171 lines
7.8 KiB

  1. ###################################################################################
  2. #
  3. # Copyright (C) 2018 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 logging
  20. from odoo import api, models, fields
  21. from odoo.osv import expression
  22. from odoo.addons.muk_utils.tools import utils
  23. _logger = logging.getLogger(__name__)
  24. class Base(models.AbstractModel):
  25. _inherit = 'base'
  26. #----------------------------------------------------------
  27. # Helper Methods
  28. #----------------------------------------------------------
  29. def _check_parent_field(self):
  30. if self._parent_name not in self._fields:
  31. raise TypeError("The parent (%s) field does not exist." % self._parent_name)
  32. def _build_search_childs_domain(self, parent_id, domain=[]):
  33. self._check_parent_field()
  34. parent_domain = [[self._parent_name, '=', parent_id]]
  35. return expression.AND([parent_domain, domain]) if domain else parent_domain
  36. #----------------------------------------------------------
  37. # Security
  38. #----------------------------------------------------------
  39. @api.multi
  40. def _filter_access(self, operation):
  41. if self.check_access_rights(operation, False):
  42. return self._filter_access_rules(operation)
  43. return self.env[self._name]
  44. @api.multi
  45. def _filter_access_ids(self, operation):
  46. return self._filter_access(operation).ids
  47. @api.multi
  48. def check_access(self, operation, raise_exception=False):
  49. try:
  50. access_right = self.check_access_rights(operation, raise_exception)
  51. access_rule = self.check_access_rule(operation) is None
  52. return access_right and access_rule
  53. except AccessError:
  54. if raise_exception:
  55. raise
  56. return False
  57. #----------------------------------------------------------
  58. # Hierarchy Methods
  59. #----------------------------------------------------------
  60. @api.model
  61. def search_parents(self, domain=[], order=None):
  62. """ This method finds the top level elements of the hierarchy for a given search query.
  63. :param domain: a search domain <reference/orm/domains> (default: empty list)
  64. :param order: a string to define the sort order of the query (default: none)
  65. :returns: the top level elements for the given search query
  66. """
  67. return self.browse(self._search_parents(domain=domain, order=order))
  68. @api.model
  69. def search_read_parents(self, domain=[], fields=None, order=None):
  70. """ This method finds the top level elements of the hierarchy for a given search query.
  71. :param domain: a search domain <reference/orm/domains> (default: empty list)
  72. :param fields: a list of fields to read (default: all fields of the model)
  73. :param order: a string to define the sort order of the query (default: none)
  74. :returns: the top level elements for the given search query
  75. """
  76. records = self.search_parents(domain=domain, order=order)
  77. if not records:
  78. return []
  79. if fields and fields == ['id']:
  80. return [{'id': record.id} for record in records]
  81. result = records.read(fields)
  82. if len(result) <= 1:
  83. return result
  84. index = {vals['id']: vals for vals in result}
  85. return [index[record.id] for record in records if record.id in index]
  86. @api.model
  87. def _search_parents(self, domain=[], order=None):
  88. self._check_parent_field()
  89. self.check_access_rights('read')
  90. if expression.is_false(self, domain):
  91. return []
  92. query = self._where_calc(domain)
  93. self._apply_ir_rules(query, 'read')
  94. from_clause, where_clause, where_clause_arguments = query.get_sql()
  95. parent_where = where_clause and (" WHERE %s" % where_clause) or ''
  96. parent_query = 'SELECT "%s".id FROM ' % self._table + from_clause + parent_where
  97. no_parent_clause ='"{table}"."{field}" IS NULL'.format(
  98. table=self._table,
  99. field=self._parent_name
  100. )
  101. no_access_clause ='"{table}"."{field}" NOT IN ({query})'.format(
  102. table=self._table,
  103. field=self._parent_name,
  104. query=parent_query
  105. )
  106. parent_clause = '({0} OR {1})'.format(
  107. no_parent_clause,
  108. no_access_clause
  109. )
  110. order_by = self._generate_order_by(order, query)
  111. from_clause, where_clause, where_clause_params = query.get_sql()
  112. where_str = (
  113. where_clause and
  114. (" WHERE %s AND %s" % (where_clause, parent_clause)) or
  115. (" WHERE %s" % parent_clause)
  116. )
  117. query_str = 'SELECT "%s".id FROM ' % self._table + from_clause + where_str + order_by
  118. complete_where_clause_params = where_clause_params + where_clause_arguments
  119. self._cr.execute(query_str, complete_where_clause_params)
  120. return utils.uniquify_list([x[0] for x in self._cr.fetchall()])
  121. @api.model
  122. def search_childs(self, parent_id, domain=[], offset=0, limit=None, order=None, count=False):
  123. """ This method finds the direct child elements of the parent record for a given search query.
  124. :param parent_id: the integer representing the ID of the parent record
  125. :param domain: a search domain <reference/orm/domains> (default: empty list)
  126. :param offset: the number of results to ignore (default: none)
  127. :param limit: maximum number of records to return (default: all)
  128. :param order: a string to define the sort order of the query (default: none)
  129. :param count: counts and returns the number of matching records (default: False)
  130. :returns: the top level elements for the given search query
  131. """
  132. domain = self._build_search_childs_domain(parent_id, domain=domain)
  133. return self.search(domain, offset=offset, limit=limit, order=order, count=count)
  134. @api.model
  135. def search_read_childs(self, parent_id, domain=[], fields=None, offset=0, limit=None, order=None):
  136. """ This method finds the direct child elements of the parent record for a given search query.
  137. :param parent_id: the integer representing the ID of the parent record
  138. :param domain: a search domain <reference/orm/domains> (default: empty list)
  139. :param fields: a list of fields to read (default: all fields of the model)
  140. :param offset: the number of results to ignore (default: none)
  141. :param limit: maximum number of records to return (default: all)
  142. :param order: a string to define the sort order of the query (default: none)
  143. :returns: the top level elements for the given search query
  144. """
  145. domain = self._build_search_childs_domain(parent_id, domain=domain)
  146. return self.search_read(domain=domain, fields=fields, offset=offset, limit=limit, order=order)