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.

186 lines
7.9 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 logging
  20. from odoo import _, api, fields, models
  21. from odoo.exceptions import UserError
  22. from odoo.osv import expression
  23. from odoo.tools import lazy
  24. _logger = logging.getLogger(__name__)
  25. class Base(models.AbstractModel):
  26. _inherit = 'base'
  27. #----------------------------------------------------------
  28. # Functions
  29. #----------------------------------------------------------
  30. @api.model
  31. def search_panel_select_range(self, field_name, **kwargs):
  32. """
  33. Return possible values of the field field_name (case select="one")
  34. and the parent field (if any) used to hierarchize them.
  35. :param field_name: the name of a many2one category field
  36. :return: {
  37. 'parent_field': parent field on the comodel of field, or False
  38. 'values': array of dictionaries containing some info on the records
  39. available on the comodel of the field 'field_name'.
  40. The display name (and possibly parent_field) are fetched.
  41. }
  42. """
  43. field = self._fields[field_name]
  44. supported_types = ['many2one']
  45. if field.type not in supported_types:
  46. raise UserError(_('Only types %(supported_types)s are supported for category (found type %(field_type)s)') % ({
  47. 'supported_types': supported_types, 'field_type': field.type}))
  48. Comodel = self.env[field.comodel_name]
  49. fields = ['display_name']
  50. parent_name = Comodel._parent_name if Comodel._parent_name in Comodel._fields else False
  51. if parent_name:
  52. fields.append(parent_name)
  53. return {
  54. 'parent_field': parent_name,
  55. 'values': Comodel.with_context(hierarchical_naming=False).search_read([], fields),
  56. }
  57. @api.model
  58. def search_panel_select_multi_range(self, field_name, **kwargs):
  59. """
  60. Return possible values of the field field_name (case select="multi"),
  61. possibly with counters and groups.
  62. :param field_name: the name of a filter field;
  63. possible types are many2one, many2many, selection.
  64. :param search_domain: base domain of search
  65. :param category_domain: domain generated by categories
  66. :param filter_domain: domain generated by filters
  67. :param comodel_domain: domain of field values (if relational)
  68. :param group_by: extra field to read on comodel, to group comodel records
  69. :param disable_counters: whether to count records by value
  70. :return: a list of possible values, each being a dict with keys
  71. 'id' (value),
  72. 'name' (value label),
  73. 'count' (how many records with that value),
  74. 'group_id' (value of group),
  75. 'group_name' (label of group).
  76. """
  77. field = self._fields[field_name]
  78. supported_types = ['many2one', 'many2many', 'selection']
  79. if field.type not in supported_types:
  80. raise UserError(_('Only types %(supported_types)s are supported for filter (found type %(field_type)s)') % ({
  81. 'supported_types': supported_types, 'field_type': field.type}))
  82. Comodel = self.env.get(field.comodel_name)
  83. model_domain = expression.AND([
  84. kwargs.get('search_domain', []),
  85. kwargs.get('category_domain', []),
  86. kwargs.get('filter_domain', []),
  87. [(field_name, '!=', False)],
  88. ])
  89. comodel_domain = kwargs.get('comodel_domain', [])
  90. disable_counters = kwargs.get('disable_counters', False)
  91. group_by = kwargs.get('group_by', False)
  92. if group_by:
  93. # determine the labeling of values returned by the group_by field
  94. group_by_field = Comodel._fields[group_by]
  95. if group_by_field.type == 'many2one':
  96. def group_id_name(value):
  97. return value or (False, _("Not Set"))
  98. elif group_by_field.type == 'selection':
  99. desc = Comodel.fields_get([group_by])[group_by]
  100. group_by_selection = dict(desc['selection'])
  101. group_by_selection[False] = _("Not Set")
  102. def group_id_name(value):
  103. return value, group_by_selection[value]
  104. else:
  105. def group_id_name(value):
  106. return (value, value) if value else (False, _("Not Set"))
  107. # get filter_values
  108. filter_values = []
  109. if field.type == 'many2one':
  110. counters = {}
  111. if not disable_counters:
  112. groups = self.read_group(model_domain, [field_name], [field_name])
  113. counters = {
  114. group[field_name][0]: group[field_name + '_count']
  115. for group in groups
  116. }
  117. # retrieve all possible values, and return them with their label and counter
  118. field_names = ['display_name', group_by] if group_by else ['display_name']
  119. records = Comodel.search_read(comodel_domain, field_names)
  120. for record in records:
  121. record_id = record['id']
  122. values = {
  123. 'id': record_id,
  124. 'name': record['display_name'],
  125. 'count': counters.get(record_id, 0),
  126. }
  127. if group_by:
  128. values['group_id'], values['group_name'] = group_id_name(record[group_by])
  129. filter_values.append(values)
  130. elif field.type == 'many2many':
  131. # retrieve all possible values, and return them with their label and counter
  132. field_names = ['display_name', group_by] if group_by else ['display_name']
  133. records = Comodel.search_read(comodel_domain, field_names)
  134. for record in records:
  135. record_id = record['id']
  136. values = {
  137. 'id': record_id,
  138. 'name': record['display_name'],
  139. 'count': 0,
  140. }
  141. if not disable_counters:
  142. count_domain = expression.AND([model_domain, [(field_name, 'in', record_id)]])
  143. values['count'] = self.search_count(count_domain)
  144. if group_by:
  145. values['group_id'], values['group_name'] = group_id_name(record[group_by])
  146. filter_values.append(values)
  147. elif field.type == 'selection':
  148. counters = {}
  149. if not disable_counters:
  150. groups = self.read_group(model_domain, [field_name], [field_name])
  151. counters = {
  152. group[field_name]: group[field_name + '_count']
  153. for group in groups
  154. }
  155. # retrieve all possible values, and return them with their label and counter
  156. selection = self.fields_get([field_name])[field_name]
  157. for value, label in selection:
  158. filter_values.append({
  159. 'id': value,
  160. 'name': label,
  161. 'count': counters.get(value, 0),
  162. })
  163. return filter_values