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.

178 lines
6.4 KiB

8 years ago
9 years ago
9 years ago
9 years ago
8 years ago
8 years ago
  1. # -*- coding: utf-8 -*-
  2. # © 2010-2013 OpenERP s.a. (<http://openerp.com>).
  3. # © 2014 initOS GmbH & Co. KG (<http://www.initos.com>).
  4. # © 2015-Today GRAP
  5. # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
  6. import datetime
  7. import time
  8. from dateutil.relativedelta import relativedelta
  9. from openerp import api, fields, models
  10. from openerp.tools.safe_eval import safe_eval as eval
  11. from openerp.tools.translate import _
  12. from openerp.exceptions import ValidationError, except_orm
  13. class TileTile(models.Model):
  14. _name = 'tile.tile'
  15. _order = 'sequence, name'
  16. def median(self, aList):
  17. # https://docs.python.org/3/library/statistics.html#statistics.median
  18. # TODO : refactor, using statistics.median when Odoo will be available
  19. # in Python 3.4
  20. even = (0 if len(aList) % 2 else 1) + 1
  21. half = (len(aList) - 1) / 2
  22. return sum(sorted(aList)[half:half + even]) / float(even)
  23. def _get_eval_context(self):
  24. def _context_today():
  25. return fields.Date.from_string(fields.Date.context_today(self))
  26. context = self.env.context.copy()
  27. context.update({
  28. 'time': time,
  29. 'datetime': datetime,
  30. 'relativedelta': relativedelta,
  31. 'context_today': _context_today,
  32. 'current_date': fields.Date.today(),
  33. })
  34. return context
  35. # Column Section
  36. name = fields.Char(required=True)
  37. sequence = fields.Integer(default=0, required=True)
  38. user_id = fields.Many2one('res.users', 'User')
  39. background_color = fields.Char(default='#0E6C7E', oldname='color')
  40. font_color = fields.Char(default='#FFFFFF')
  41. model_id = fields.Many2one('ir.model', 'Model', required=True)
  42. domain = fields.Text(default='[]')
  43. action_id = fields.Many2one('ir.actions.act_window', 'Action')
  44. count = fields.Integer(compute='_compute_data')
  45. computed_value = fields.Float(compute='_compute_data')
  46. field_function = fields.Selection([
  47. ('min', 'Minimum'),
  48. ('max', 'Maximum'),
  49. ('sum', 'Sum'),
  50. ('avg', 'Average'),
  51. ('median', 'Median'),
  52. ], string='Function')
  53. field_id = fields.Many2one(
  54. 'ir.model.fields',
  55. string='Field',
  56. domain="[('model_id', '=', model_id),"
  57. " ('ttype', 'in', ['float', 'int'])]")
  58. helper = fields.Char(compute='_compute_function_helper')
  59. active = fields.Boolean(
  60. compute='_compute_active',
  61. search='_search_active',
  62. readonly=True)
  63. @api.one
  64. def _compute_data(self):
  65. self.count = 0
  66. self.computed_value = 0
  67. if self.active:
  68. # Compute count item
  69. model = self.env[self.model_id.model]
  70. eval_context = self._get_eval_context()
  71. self.count = model.search_count(eval(self.domain, eval_context))
  72. # Compute datas for field_id depending of field_function
  73. if self.field_function and self.field_id and self.count != 0:
  74. records = model.search(eval(self.domain, eval_context))
  75. vals = [x[self.field_id.name] for x in records]
  76. if self.field_function == 'min':
  77. self.computed_value = min(vals)
  78. elif self.field_function == 'max':
  79. self.computed_value = max(vals)
  80. elif self.field_function == 'sum':
  81. self.computed_value = sum(vals)
  82. elif self.field_function == 'avg':
  83. self.computed_value = sum(vals) / len(vals)
  84. elif self.field_function == 'median':
  85. self.computed_value = self.median(vals)
  86. @api.one
  87. @api.onchange('field_function', 'field_id')
  88. def _compute_function_helper(self):
  89. self.helper = ''
  90. if self.field_function and self.field_id:
  91. desc = self.field_id.field_description
  92. helpers = {
  93. 'min': "Minimum value of '%s'",
  94. 'max': "Maximum value of '%s'",
  95. 'sum': "Total value of '%s'",
  96. 'avg': "Average value of '%s'",
  97. 'median': "Median value of '%s'",
  98. }
  99. self.helper = _(helpers.get(self.field_function, '')) % desc
  100. @api.one
  101. def _compute_active(self):
  102. ima = self.env['ir.model.access']
  103. self.active = ima.check(self.model_id.model, 'read', False)
  104. def _search_active(self, operator, value):
  105. cr = self.env.cr
  106. if operator != '=':
  107. raise except_orm(
  108. _('Unimplemented Feature. Search on Active field disabled.'))
  109. ima = self.env['ir.model.access']
  110. ids = []
  111. cr.execute("""
  112. SELECT tt.id, im.model
  113. FROM tile_tile tt
  114. INNER JOIN ir_model im
  115. ON tt.model_id = im.id""")
  116. for result in cr.fetchall():
  117. if (ima.check(result[1], 'read', False) == value):
  118. ids.append(result[0])
  119. return [('id', 'in', ids)]
  120. # Constraints and onchanges
  121. @api.one
  122. @api.constrains('model_id', 'field_id')
  123. def _check_model_id_field_id(self):
  124. if self.field_id and self.field_id.model_id.id != self.model_id.id:
  125. raise ValidationError(
  126. _("Please select a field from the selected model."))
  127. @api.one
  128. @api.constrains('field_id', 'field_function')
  129. def _check_field_id_field_function(self):
  130. validations = self.field_id, self.field_function
  131. if any(validations) and not all(validations):
  132. raise ValidationError(
  133. _("Please set both: 'Field' and 'Function'."))
  134. # Action methods
  135. @api.multi
  136. def open_link(self):
  137. res = {
  138. 'name': self.name,
  139. 'view_type': 'form',
  140. 'view_mode': 'tree',
  141. 'view_id': [False],
  142. 'res_model': self.model_id.model,
  143. 'type': 'ir.actions.act_window',
  144. 'context': self.env.context,
  145. 'nodestroy': True,
  146. 'target': 'current',
  147. 'domain': self.domain,
  148. }
  149. if self.action_id:
  150. res.update(self.action_id.read(
  151. ['view_type', 'view_mode', 'type'])[0])
  152. return res
  153. @api.model
  154. def add(self, vals):
  155. if 'model_id' in vals and not vals['model_id'].isdigit():
  156. # need to replace model_name with its id
  157. vals['model_id'] = self.env['ir.model'].search(
  158. [('model', '=', vals['model_id'])]).id
  159. self.create(vals)