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.

188 lines
8.5 KiB

  1. ###################################################################################
  2. #
  3. # Copyright (c) 2017-2019 MuK IT GmbH.
  4. #
  5. # This file is part of MuK Utils
  6. # (see https://mukit.at).
  7. #
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU Lesser General Public License as published by
  10. # the Free Software Foundation, either version 3 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU Lesser General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU Lesser General Public License
  19. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. #
  21. ###################################################################################
  22. import logging
  23. from odoo import api, models, fields
  24. from odoo.osv import expression
  25. from odoo.addons.muk_utils.tools import utils
  26. _logger = logging.getLogger(__name__)
  27. class Base(models.AbstractModel):
  28. _inherit = 'base'
  29. #----------------------------------------------------------
  30. # Helper Methods
  31. #----------------------------------------------------------
  32. @api.model
  33. def _check_parent_field(self):
  34. if self._parent_name not in self._fields:
  35. raise TypeError("The parent (%s) field does not exist." % self._parent_name)
  36. @api.model
  37. def _build_search_childs_domain(self, parent_id, domain=[]):
  38. self._check_parent_field()
  39. parent_domain = [[self._parent_name, '=', parent_id]]
  40. return expression.AND([parent_domain, domain]) if domain else parent_domain
  41. @api.model
  42. def _check_context_bin_size(self, field):
  43. return any(
  44. key in self.env.context and self.env.context[key]
  45. for key in ['bin_size', 'bin_size_%s' % (field)]
  46. )
  47. #----------------------------------------------------------
  48. # Security
  49. #----------------------------------------------------------
  50. @api.multi
  51. def _filter_access(self, operation):
  52. if self.check_access_rights(operation, False):
  53. return self._filter_access_rules(operation)
  54. return self.env[self._name]
  55. @api.multi
  56. def _filter_access_ids(self, operation):
  57. return self._filter_access(operation).ids
  58. @api.multi
  59. def check_access(self, operation, raise_exception=False):
  60. try:
  61. access_right = self.check_access_rights(operation, raise_exception)
  62. access_rule = self.check_access_rule(operation) is None
  63. return access_right and access_rule
  64. except AccessError:
  65. if raise_exception:
  66. raise
  67. return False
  68. #----------------------------------------------------------
  69. # Hierarchy Methods
  70. #----------------------------------------------------------
  71. @api.model
  72. def search_parents(self, domain=[], offset=0, limit=None, order=None, count=False):
  73. """ This method finds the top level elements of the hierarchy for a given search query.
  74. :param domain: a search domain <reference/orm/domains> (default: empty list)
  75. :param order: a string to define the sort order of the query (default: none)
  76. :returns: the top level elements for the given search query
  77. """
  78. res = self._search_parents(domain=domain, offset=offset, limit=limit, order=order, count=count)
  79. return res if count else self.browse(res)
  80. @api.model
  81. def search_read_parents(self, domain=[], fields=None, offset=0, limit=None, order=None):
  82. """ This method finds the top level elements of the hierarchy for a given search query.
  83. :param domain: a search domain <reference/orm/domains> (default: empty list)
  84. :param fields: a list of fields to read (default: all fields of the model)
  85. :param order: a string to define the sort order of the query (default: none)
  86. :returns: the top level elements for the given search query
  87. """
  88. records = self.search_parents(domain=domain, offset=offset, limit=limit, order=order)
  89. if not records:
  90. return []
  91. if fields and fields == ['id']:
  92. return [{'id': record.id} for record in records]
  93. result = records.read(fields)
  94. if len(result) <= 1:
  95. return result
  96. index = {vals['id']: vals for vals in result}
  97. return [index[record.id] for record in records if record.id in index]
  98. @api.model
  99. def _search_parents(self, domain=[], offset=0, limit=None, order=None, count=False):
  100. self._check_parent_field()
  101. self.check_access_rights('read')
  102. if expression.is_false(self, domain):
  103. return []
  104. query = self._where_calc(domain)
  105. self._apply_ir_rules(query, 'read')
  106. from_clause, where_clause, where_clause_arguments = query.get_sql()
  107. parent_where = where_clause and (" WHERE %s" % where_clause) or ''
  108. parent_query = 'SELECT "%s".id FROM ' % self._table + from_clause + parent_where
  109. no_parent_clause ='"{table}"."{field}" IS NULL'.format(
  110. table=self._table,
  111. field=self._parent_name
  112. )
  113. no_access_clause ='"{table}"."{field}" NOT IN ({query})'.format(
  114. table=self._table,
  115. field=self._parent_name,
  116. query=parent_query
  117. )
  118. parent_clause = '({0} OR {1})'.format(
  119. no_parent_clause,
  120. no_access_clause
  121. )
  122. order_by = self._generate_order_by(order, query)
  123. from_clause, where_clause, where_clause_params = query.get_sql()
  124. where_str = (
  125. where_clause and
  126. (" WHERE %s AND %s" % (where_clause, parent_clause)) or
  127. (" WHERE %s" % parent_clause)
  128. )
  129. if count:
  130. query_str = 'SELECT count(1) FROM ' + from_clause + where_str
  131. self._cr.execute(query_str, where_clause_params)
  132. return self._cr.fetchone()[0]
  133. limit_str = limit and ' limit %d' % limit or ''
  134. offset_str = offset and ' offset %d' % offset or ''
  135. query_str = 'SELECT "%s".id FROM ' % self._table + from_clause + where_str + order_by + limit_str + offset_str
  136. complete_where_clause_params = where_clause_params + where_clause_arguments
  137. self._cr.execute(query_str, complete_where_clause_params)
  138. return utils.uniquify_list([x[0] for x in self._cr.fetchall()])
  139. @api.model
  140. def search_childs(self, parent_id, domain=[], offset=0, limit=None, order=None, count=False):
  141. """ This method finds the direct child elements of the parent record for a given search query.
  142. :param parent_id: the integer representing the ID of the parent record
  143. :param domain: a search domain <reference/orm/domains> (default: empty list)
  144. :param offset: the number of results to ignore (default: none)
  145. :param limit: maximum number of records to return (default: all)
  146. :param order: a string to define the sort order of the query (default: none)
  147. :param count: counts and returns the number of matching records (default: False)
  148. :returns: the top level elements for the given search query
  149. """
  150. domain = self._build_search_childs_domain(parent_id, domain=domain)
  151. return self.search(domain, offset=offset, limit=limit, order=order, count=count)
  152. @api.model
  153. def search_read_childs(self, parent_id, domain=[], fields=None, offset=0, limit=None, order=None):
  154. """ This method finds the direct child elements of the parent record for a given search query.
  155. :param parent_id: the integer representing the ID of the parent record
  156. :param domain: a search domain <reference/orm/domains> (default: empty list)
  157. :param fields: a list of fields to read (default: all fields of the model)
  158. :param offset: the number of results to ignore (default: none)
  159. :param limit: maximum number of records to return (default: all)
  160. :param order: a string to define the sort order of the query (default: none)
  161. :returns: the top level elements for the given search query
  162. """
  163. domain = self._build_search_childs_domain(parent_id, domain=domain)
  164. return self.search_read(domain=domain, fields=fields, offset=offset, limit=limit, order=order)