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.

328 lines
11 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 openerp import api, models
  5. from openerp.modules.registry import RegistryManager
  6. NO_BI_MODELS = [
  7. 'temp.range',
  8. 'account.statement.operation.template',
  9. 'fetchmail.server'
  10. ]
  11. NO_BI_FIELDS = [
  12. 'id',
  13. 'create_uid',
  14. 'create_date',
  15. 'write_uid',
  16. 'write_date'
  17. ]
  18. NO_BI_TTYPES = [
  19. 'many2many',
  20. 'one2many',
  21. 'html',
  22. 'binary',
  23. 'reference'
  24. ]
  25. def dict_for_field(field):
  26. return {
  27. 'id': field.id,
  28. 'name': field.name,
  29. 'description': field.field_description,
  30. 'type': field.ttype,
  31. 'relation': field.relation,
  32. 'custom': False,
  33. 'model_id': field.model_id.id,
  34. 'model': field.model_id.model,
  35. 'model_name': field.model_id.name
  36. }
  37. class IrModel(models.Model):
  38. _inherit = 'ir.model'
  39. @api.model
  40. def _filter_bi_fields(self, ir_model_field_obj):
  41. name = ir_model_field_obj.name
  42. model = ir_model_field_obj.model_id
  43. model_name = model.model
  44. if model_name[0:6] != 'x_bve.':
  45. Model = self.env[model_name]
  46. if name in Model._columns:
  47. f = Model._columns[name]
  48. return f._classic_write
  49. return False
  50. @api.model
  51. def _filter_bi_models(self, model):
  52. def _check_name(model_model):
  53. if model_model in NO_BI_MODELS:
  54. return 1
  55. return 0
  56. def _check_startswith(model_model):
  57. if model_model.startswith('workflow') or \
  58. model_model.startswith('ir.') or \
  59. model_model.startswith('base_'):
  60. return 1
  61. return 0
  62. def _check_contains(model_model):
  63. if 'mail' in model_model or \
  64. '_' in model_model or \
  65. 'report' in model_model or \
  66. 'edi.' in model_model:
  67. return 1
  68. return 0
  69. def _check_unknow(model_name):
  70. if model_name == 'Unknow' or '.' in model_name:
  71. return 1
  72. return 0
  73. model_model = model['model']
  74. model_name = model['name']
  75. count_check = 0
  76. count_check += _check_name(model_model)
  77. count_check += _check_startswith(model_model)
  78. count_check += _check_contains(model_model)
  79. count_check += _check_unknow(model_name)
  80. if not count_check:
  81. return self.env['ir.model.access'].check(
  82. model['model'], 'read', False)
  83. return False
  84. @api.model
  85. def get_related_fields(self, model_ids):
  86. """ Return list of field dicts for all fields that can be
  87. joined with models in model_ids
  88. """
  89. Model = self.env['ir.model']
  90. domain = [('id', 'in', model_ids.values())]
  91. models = Model.sudo().search(domain)
  92. model_names = {}
  93. for model in models:
  94. model_names.update({model.id: model.model})
  95. related_fields = self._get_related_fields_list(model_ids, model_names)
  96. return related_fields
  97. @api.model
  98. def _get_related_fields_list(self, model_ids, model_names):
  99. def _get_right_fields(model_ids, model_names):
  100. Fields = self.env['ir.model.fields']
  101. rfields = []
  102. domain = [('model_id', 'in', model_ids.values()),
  103. ('ttype', 'in', ['many2one'])]
  104. for field in filter(
  105. self._filter_bi_fields,
  106. Fields.sudo().search(domain)):
  107. for model in model_ids.items():
  108. if model[1] == field.model_id.id:
  109. rfields.append(
  110. dict(dict_for_field(field),
  111. join_node=-1,
  112. table_alias=model[0])
  113. )
  114. return rfields
  115. def _get_left_fields(model_ids, model_names):
  116. Fields = self.env['ir.model.fields']
  117. lfields = []
  118. domain = [('relation', 'in', model_names.values()),
  119. ('ttype', 'in', ['many2one'])]
  120. for field in filter(
  121. self._filter_bi_fields,
  122. Fields.sudo().search(domain)):
  123. for model in model_ids.items():
  124. if model_names[model[1]] == field['relation']:
  125. lfields.append(
  126. dict(dict_for_field(field),
  127. join_node=model[0],
  128. table_alias=-1)
  129. )
  130. return lfields
  131. def _get_relation_list(model_ids, model_names, lfields):
  132. relation_list = []
  133. for model in model_ids.items():
  134. for field in lfields:
  135. if model_names[model[1]] == field['relation']:
  136. relation_list.append(
  137. dict(field, join_node=model[0])
  138. )
  139. return relation_list
  140. def _get_model_list(model_ids, rfields):
  141. model_list = []
  142. for model in model_ids.items():
  143. for field in rfields:
  144. if model[1] == field['model_id']:
  145. model_list.append(
  146. dict(field, table_alias=model[0])
  147. )
  148. return model_list
  149. lfields = _get_left_fields(model_ids, model_names)
  150. rfields = _get_right_fields(model_ids, model_names)
  151. relation_list = _get_relation_list(model_ids, model_names, lfields)
  152. model_list = _get_model_list(model_ids, rfields)
  153. related_fields = relation_list + model_list
  154. return related_fields
  155. @api.model
  156. def get_related_models(self, model_ids):
  157. """ Return list of model dicts for all models that can be
  158. joined with models in model_ids
  159. """
  160. def _get_field(fields, orig, target):
  161. field_list = []
  162. for f in fields:
  163. if f[orig] == -1:
  164. field_list.append(f[target])
  165. return field_list
  166. def _get_list_id(model_ids, fields):
  167. list_model = model_ids.values()
  168. list_model += _get_field(fields, 'table_alias', 'model_id')
  169. return list_model
  170. def _get_list_relation(fields):
  171. list_model = _get_field(fields, 'join_node', 'relation')
  172. return list_model
  173. models_list = []
  174. related_fields = self.get_related_fields(model_ids)
  175. list_id = _get_list_id(model_ids, related_fields)
  176. list_model = _get_list_relation(related_fields)
  177. domain = ['|',
  178. ('id', 'in', list_id),
  179. ('model', 'in', list_model)]
  180. models = self.env['ir.model'].sudo().search(domain)
  181. for model in models:
  182. models_list.append({
  183. 'id': model.id,
  184. 'name': model.name,
  185. 'model': model.model
  186. })
  187. return sorted(
  188. filter(self._filter_bi_models, models_list),
  189. key=lambda x: x['name']
  190. )
  191. @api.model
  192. def get_models(self):
  193. """ Return list of model dicts for all available models.
  194. """
  195. def dict_for_model(model):
  196. return {
  197. 'id': model.id,
  198. 'name': model.name,
  199. 'model': model.model
  200. }
  201. models_domain = [('transient', '=', False)]
  202. return sorted(filter(
  203. self._filter_bi_models,
  204. [dict_for_model(model)
  205. for model in self.search(models_domain)]),
  206. key=lambda x: x['name'])
  207. @api.model
  208. def get_join_nodes(self, field_data, new_field):
  209. """ Return list of field dicts of join nodes
  210. Return all possible join nodes to add new_field to the query
  211. containing model_ids.
  212. """
  213. def _get_model_ids(field_data):
  214. model_ids = dict([(field['table_alias'],
  215. field['model_id']) for field in field_data])
  216. return model_ids
  217. def _get_join_nodes_dict(model_ids, new_field):
  218. join_nodes = []
  219. for alias, model_id in model_ids.items():
  220. if model_id == new_field['model_id']:
  221. join_nodes.append({'table_alias': alias})
  222. for dict_field in self.get_related_fields(model_ids):
  223. condition = [
  224. dict_field['join_node'] == -1,
  225. dict_field['table_alias'] == -1
  226. ]
  227. relation = (new_field['model'] == dict_field['relation'])
  228. model = (new_field['model_id'] == dict_field['model_id'])
  229. if (relation and condition[0]) or (model and condition[1]):
  230. join_nodes.append(dict_field)
  231. return join_nodes
  232. model_ids = _get_model_ids(field_data)
  233. keys = [(field['table_alias'], field['id'])
  234. for field in field_data if field.get('join_node', -1) != -1]
  235. join_nodes = _get_join_nodes_dict(model_ids, new_field)
  236. return filter(
  237. lambda x: 'id' not in x or
  238. (x['table_alias'], x['id']) not in keys, join_nodes)
  239. @api.model
  240. def get_fields(self, model_id):
  241. bi_field_domain = [
  242. ('model_id', '=', model_id),
  243. ('name', 'not in', NO_BI_FIELDS),
  244. ('ttype', 'not in', NO_BI_TTYPES)
  245. ]
  246. Fields = self.env['ir.model.fields']
  247. fields = filter(
  248. self._filter_bi_fields,
  249. Fields.sudo().search(bi_field_domain)
  250. )
  251. fields_dict = []
  252. for field in fields:
  253. fields_dict.append(
  254. {'id': field.id,
  255. 'model_id': model_id,
  256. 'name': field.name,
  257. 'description': field.field_description,
  258. 'type': field.ttype,
  259. 'custom': False,
  260. 'model': field.model_id.model,
  261. 'model_name': field.model_id.name
  262. }
  263. )
  264. sorted_fields = sorted(
  265. fields_dict,
  266. key=lambda x: x['description'],
  267. reverse=True
  268. )
  269. return sorted_fields
  270. @api.model
  271. def create(self, vals):
  272. if self._context and self._context.get('bve'):
  273. vals['state'] = 'base'
  274. res = super(IrModel, self).create(vals)
  275. # this sql update is necessary since a write method here would
  276. # be not working (an orm constraint is restricting the modification
  277. # of the state field while updating ir.model)
  278. q = ("""UPDATE ir_model SET state = 'manual'
  279. WHERE id = """ + str(res.id))
  280. self.env.cr.execute(q)
  281. # update registry
  282. if self._context.get('bve'):
  283. # setup models; this reloads custom models in registry
  284. self.pool.setup_models(self._cr, partial=(not self.pool.ready))
  285. # signal that registry has changed
  286. RegistryManager.signal_registry_change(self.env.cr.dbname)
  287. return res