OCA reporting engine fork for dev and update.
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.

259 lines
8.3 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2015-2017 Onestein (<http://www.onestein.eu>)
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. from odoo import api, models
  5. NO_BI_MODELS = [
  6. 'temp.range',
  7. 'account.statement.operation.template',
  8. 'fetchmail.server'
  9. ]
  10. NO_BI_FIELDS = [
  11. 'id',
  12. 'create_uid',
  13. 'create_date',
  14. 'write_uid',
  15. 'write_date'
  16. ]
  17. NO_BI_TTYPES = [
  18. 'many2many',
  19. 'one2many',
  20. 'html',
  21. 'binary',
  22. 'reference'
  23. ]
  24. def dict_for_field(field):
  25. return {
  26. 'id': field.id,
  27. 'name': field.name,
  28. 'description': field.field_description,
  29. 'type': field.ttype,
  30. 'relation': field.relation,
  31. 'custom': False,
  32. 'model_id': field.model_id.id,
  33. 'model': field.model_id.model,
  34. 'model_name': field.model_id.name
  35. }
  36. def dict_for_model(model):
  37. return {
  38. 'id': model.id,
  39. 'name': model.name,
  40. 'model': model.model
  41. }
  42. class IrModel(models.Model):
  43. _inherit = 'ir.model'
  44. @api.model
  45. def _filter_bi_models(self, model):
  46. def _check_name(model_model):
  47. if model_model in NO_BI_MODELS:
  48. return 1
  49. return 0
  50. def _check_startswith(model_model):
  51. if model_model.startswith('workflow') or \
  52. model_model.startswith('ir.') or \
  53. model_model.startswith('base_'):
  54. return 1
  55. return 0
  56. def _check_contains(model_model):
  57. if 'mail' in model_model or \
  58. '_' in model_model or \
  59. 'report' in model_model or \
  60. 'edi.' in model_model:
  61. return 1
  62. return 0
  63. def _check_unknow(model_name):
  64. if model_name == 'Unknow' or '.' in model_name:
  65. return 1
  66. return 0
  67. model_model = model['model']
  68. model_name = model['name']
  69. count_check = 0
  70. count_check += _check_name(model_model)
  71. count_check += _check_startswith(model_model)
  72. count_check += _check_contains(model_model)
  73. count_check += _check_unknow(model_name)
  74. if not count_check:
  75. return self.env['ir.model.access'].check(
  76. model['model'], 'read', False)
  77. return False
  78. @api.model
  79. def sort_filter_models(self, models_list):
  80. res = sorted(
  81. filter(self._filter_bi_models, models_list),
  82. key=lambda x: x['name'])
  83. return res
  84. @api.model
  85. def _search_fields(self, domain):
  86. Fields = self.env['ir.model.fields']
  87. fields = Fields.sudo().search(domain)
  88. return fields
  89. @api.model
  90. def get_related_fields(self, model_ids):
  91. """ Return list of field dicts for all fields that can be
  92. joined with models in model_ids
  93. """
  94. def get_model_list(model_ids):
  95. model_list = []
  96. domain = [('model_id', 'in', model_ids.values()),
  97. ('store', '=', True),
  98. ('ttype', 'in', ['many2one'])]
  99. filtered_fields = self._search_fields(domain)
  100. for model in model_ids.items():
  101. for field in filtered_fields:
  102. if model[1] == field.model_id.id:
  103. model_list.append(
  104. dict(dict_for_field(field),
  105. join_node=-1,
  106. table_alias=model[0])
  107. )
  108. return model_list
  109. def get_relation_list(model_ids, model_names):
  110. relation_list = []
  111. domain = [('relation', 'in', model_names.values()),
  112. ('store', '=', True),
  113. ('ttype', 'in', ['many2one'])]
  114. filtered_fields = self._search_fields(domain)
  115. for model in model_ids.items():
  116. for field in filtered_fields:
  117. if model_names[model[1]] == field['relation']:
  118. relation_list.append(
  119. dict(dict_for_field(field),
  120. join_node=model[0],
  121. table_alias=-1)
  122. )
  123. return relation_list
  124. models = self.sudo().browse(model_ids.values())
  125. model_names = {}
  126. for model in models:
  127. model_names.update({model.id: model.model})
  128. model_list = get_model_list(model_ids)
  129. relation_list = get_relation_list(model_ids, model_names)
  130. return relation_list + model_list
  131. @api.model
  132. def get_related_models(self, model_ids):
  133. """ Return list of model dicts for all models that can be
  134. joined with the already selected models.
  135. """
  136. def _get_field(fields, orig, target):
  137. field_list = []
  138. for f in fields:
  139. if f[orig] == -1:
  140. field_list.append(f[target])
  141. return field_list
  142. def _get_list_id(model_ids, fields):
  143. list_model = model_ids.values()
  144. list_model += _get_field(fields, 'table_alias', 'model_id')
  145. return list_model
  146. def _get_list_relation(fields):
  147. list_model = _get_field(fields, 'join_node', 'relation')
  148. return list_model
  149. models_list = []
  150. related_fields = self.get_related_fields(model_ids)
  151. list_id = _get_list_id(model_ids, related_fields)
  152. list_model = _get_list_relation(related_fields)
  153. domain = ['|',
  154. ('id', 'in', list_id),
  155. ('model', 'in', list_model)]
  156. for model in self.sudo().search(domain):
  157. models_list.append(dict_for_model(model))
  158. return self.sort_filter_models(models_list)
  159. @api.model
  160. def get_models(self):
  161. """ Return list of model dicts for all available models.
  162. """
  163. models_list = []
  164. for model in self.search([('transient', '=', False)]):
  165. models_list.append(dict_for_model(model))
  166. return self.sort_filter_models(models_list)
  167. @api.model
  168. def get_join_nodes(self, field_data, new_field):
  169. """ Return list of field dicts of join nodes
  170. Return all possible join nodes to add new_field to the query
  171. containing model_ids.
  172. """
  173. def _get_model_ids(field_data):
  174. model_ids = dict([(field['table_alias'],
  175. field['model_id']) for field in field_data])
  176. return model_ids
  177. def _get_join_nodes_dict(model_ids, new_field):
  178. join_nodes = []
  179. for alias, model_id in model_ids.items():
  180. if model_id == new_field['model_id']:
  181. join_nodes.append({'table_alias': alias})
  182. for field in self.get_related_fields(model_ids):
  183. c = [field['join_node'] == -1, field['table_alias'] == -1]
  184. a = (new_field['model'] == field['relation'])
  185. b = (new_field['model_id'] == field['model_id'])
  186. if (a and c[0]) or (b and c[1]):
  187. join_nodes.append(field)
  188. return join_nodes
  189. model_ids = _get_model_ids(field_data)
  190. keys = [(field['table_alias'], field['id'])
  191. for field in field_data if field.get('join_node', -1) != -1]
  192. join_nodes = _get_join_nodes_dict(model_ids, new_field)
  193. return filter(
  194. lambda x: 'id' not in x or
  195. (x['table_alias'], x['id']) not in keys, join_nodes)
  196. @api.model
  197. def get_fields(self, model_id):
  198. domain = [
  199. ('model_id', '=', model_id),
  200. ('store', '=', True),
  201. ('name', 'not in', NO_BI_FIELDS),
  202. ('ttype', 'not in', NO_BI_TTYPES)
  203. ]
  204. fields_dict = []
  205. filtered_fields = self._search_fields(domain)
  206. for field in filtered_fields:
  207. fields_dict.append(
  208. {'id': field.id,
  209. 'model_id': model_id,
  210. 'name': field.name,
  211. 'description': field.field_description,
  212. 'type': field.ttype,
  213. 'custom': False,
  214. 'model': field.model_id.model,
  215. 'model_name': field.model_id.name
  216. }
  217. )
  218. sorted_fields = sorted(
  219. fields_dict,
  220. key=lambda x: x['description'],
  221. reverse=True
  222. )
  223. return sorted_fields