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.

283 lines
12 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. from openerp.osv import osv,fields as old_fields
  2. from openerp import api, models, fields, tools
  3. from openerp.tools.safe_eval import safe_eval
  4. try:
  5. from openerp.addons.email_template.email_template import mako_template_env
  6. except ImportError:
  7. try:
  8. from openerp.addons.mail.mail_template import mako_template_env
  9. except ImportError:
  10. pass
  11. import copy
  12. from openerp.tools.translate import _
  13. from datetime import date, datetime, timedelta
  14. from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
  15. from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
  16. class mail_wall_widgets_widget(models.Model):
  17. _name = 'mail.wall.widgets.widget'
  18. _order = "sequence, id"
  19. _columns = {
  20. 'name': old_fields.char('Name', required=True, translate=True),
  21. 'type': old_fields.selection(string='Type', selection=[
  22. ('list', 'List'),
  23. ('funnel', 'Funnel'),
  24. ('slice', 'Slice'),
  25. #('', ''),
  26. #('', ''),
  27. #('', ''),
  28. #('', ''),
  29. ], help='''
  30. Slice - use "domain" for total and "won_domain" for target
  31. '''),
  32. 'description': old_fields.text('Description', translate=True),
  33. 'group_ids': old_fields.many2many('res.groups', relation='mail_wall_widgets_widget_group', column1='widget_id', column2='group_id', string='Groups', help="User groups to show widget"),
  34. 'model_id': old_fields.many2one('ir.model', string='Model', help='The model object for the field to evaluate'),
  35. 'domain': old_fields.char("Filter Domain", help="Domain for filtering records. General rule, not user depending, e.g. [('state', '=', 'done')]. The expression can contain reference to 'user' which is a browse record of the current user if not in batch mode.", required=True),
  36. 'limit': old_fields.integer('Limit', help='Limit count of records to show'),
  37. 'order': old_fields.char('Order', help='Order of records to show'),
  38. 'value_field_id': old_fields.many2one('ir.model.fields',
  39. string='Value field',
  40. help='The field containing the value of record'),
  41. 'stage_field_id': old_fields.many2one('ir.model.fields',
  42. string='Stage field',
  43. help='Field to split records in funnel. It can be selection type or many2one (the later should have "sequence" field)'),
  44. #'stage_field_domain': old_fields.many2one('ir.model.fields',
  45. # string='Stage field domain',
  46. # help='(for many2one stage_field_id) Domain to find stage objects'),
  47. 'won_domain': old_fields.char('Won domain',
  48. help='Domain to find won objects'),
  49. 'field_date_id': old_fields.many2one('ir.model.fields',
  50. string='Date Field',
  51. help='The date to use for the time period evaluated'),
  52. 'start_date': old_fields.date('Start Date'),
  53. 'end_date': old_fields.date('End Date'), # no start and end = always active
  54. 'content': old_fields.char('Line template', help='Mako template to show content'),
  55. 'value_field_monetary': old_fields.boolean('Value is monetary'),
  56. 'cache': old_fields.boolean('Cache'),
  57. 'active': old_fields.boolean('Active'),
  58. 'sequence': old_fields.integer('Sequence', help='Sequence number for ordering'),
  59. }
  60. precision = fields.Float('Precision', help='round(Value/precision) * precision. E.g. 12345,333333 will be rounded to 12345,33 for precision=0.01, and to 12000 for precision=1000', default=0.01)
  61. agenda = fields.Boolean('Agenda', help='Split records by date: overdue, today, tomorrow, later')
  62. _defaults = {
  63. 'active': True,
  64. 'cache': False,
  65. 'limit': None,
  66. 'order': None,
  67. }
  68. @api.one
  69. def get_data(self, user):
  70. domain = safe_eval(self.domain, {'user': user})
  71. won_domain = safe_eval(self.won_domain or '[]', {'user': user})
  72. field_date_name = self.field_date_id and self.field_date_id.name
  73. if self.start_date and field_date_name:
  74. domain.append((field_date_name, '>=', self.start_date))
  75. if self.end_date and field_date_name:
  76. domain.append((field_date_name, '<=', self.end_date))
  77. res = {
  78. 'name': self.name,
  79. 'type': self.type,
  80. 'model': self.model_id.model,
  81. 'domain': str(domain),
  82. 'precision': self.precision,
  83. }
  84. obj = self.env[self.model_id.model]
  85. if self.type == 'list':
  86. total_count = obj.search_count(domain)
  87. groups = [{'test': lambda r: True}]
  88. if self.agenda:
  89. today = date.today()
  90. tomorrow = today + timedelta(days=1)
  91. def r2date(r):
  92. d = getattr(r, field_date_name)
  93. if d:
  94. d = datetime.strptime(d, self.field_date_id.ttype=='date' and DEFAULT_SERVER_DATE_FORMAT or DEFAULT_SERVER_DATETIME_FORMAT)
  95. d = d.date()
  96. else:
  97. d = date.today()
  98. return d
  99. groups = [
  100. {
  101. 'label': _('Overdue'),
  102. 'class': 'overdue',
  103. 'test': lambda r: r2date(r) < today,
  104. 'mandatory': False,
  105. },
  106. {
  107. 'label': _('Today'),
  108. 'class': 'today',
  109. 'test': lambda r: r2date(r) == today,
  110. 'mandatory': True,
  111. },
  112. {
  113. 'label': _('Tomorrow'),
  114. 'class': 'tomorrow',
  115. 'test': lambda r: r2date(r) == tomorrow,
  116. 'mandatory': False,
  117. },
  118. {
  119. 'label': _('Later'),
  120. 'class': 'later',
  121. 'test': lambda r: r2date(r) > tomorrow,
  122. 'mandatory': False,
  123. },
  124. ]
  125. for g in groups:
  126. g['lines'] = []
  127. res.update({
  128. 'more': self.limit and self.limit < total_count,
  129. 'total_count': total_count,
  130. 'agenda': self.agenda,
  131. 'groups': groups,
  132. })
  133. for r in obj.search(domain, limit=self.limit, order=self.order):
  134. mako = mako_template_env.from_string(tools.ustr(self.content))
  135. content = mako.render({'record':r})
  136. r_json = {
  137. 'id': r.id,
  138. #'fields': dict( (f,getattr(r,f)) for f in fields),
  139. 'display_mode': 'progress',
  140. 'state': 'inprogress',
  141. 'completeness': 0,
  142. 'name': content,
  143. 'description': '',
  144. }
  145. if self.value_field_id:
  146. r_json['current'] = getattr(r, self.value_field_id.name)
  147. if self.value_field_monetary:
  148. r_json['monetary'] = 1
  149. for g in groups:
  150. if g['test'](r):
  151. g['lines'].append(r_json)
  152. break
  153. for g in groups:
  154. del g['test']
  155. elif self.type == 'funnel':
  156. stage_ids = [] # [key]
  157. for group in obj.read_group(domain, [], [self.stage_field_id.name]):
  158. key = group[self.stage_field_id.name]
  159. if isinstance(key, (list, tuple)):
  160. key = key[0]
  161. stage_ids.append(key)
  162. stages = [] # [{'name':Name, 'id': key}]
  163. if self.stage_field_id.ttype == 'selection':
  164. d = dict (self.stage_field_id.selection)
  165. stages = [ {'id':id, 'name':d[id]} for id in stage_ids ]
  166. else: # many2one
  167. stage_model = self.stage_field_id.relation
  168. for r in self.env[stage_model].browse(stage_ids):
  169. stages.append({'id': r.id, 'name':r.name_get()[0][1]})
  170. value_field_name = self.value_field_id.name
  171. for stage in stages:
  172. d = copy.copy(domain)
  173. d.append( (self.stage_field_id.name, '=', stage['id']) )
  174. result = obj.read_group(d, [value_field_name], [])
  175. stage['closed_value'] = result and result[0][value_field_name] or 0.0
  176. stage['domain'] = str(d)
  177. # won value
  178. d = domain + won_domain
  179. result = obj.read_group(domain, [value_field_name], [])
  180. won = {'name': _('Won'),
  181. 'id':'__won__',
  182. 'closed_value': result and result[0][value_field_name] or 0.0
  183. }
  184. stages.append(won)
  185. cur = 0
  186. for stage in reversed(stages):
  187. cur += stage['closed_value']
  188. stage['abs_value'] = cur
  189. total_value = stages[0]['abs_value']
  190. precision = self.precision
  191. for s in stages:
  192. s['rel_value'] = round(100*s['abs_value']/total_value/precision)*precision if total_value else 100
  193. # dummy fields
  194. s['display_mode'] = 'progress'
  195. s['monetary'] = 1
  196. res['stages'] = stages
  197. res['won'] = won
  198. res['conversion_rate'] = stages[-1]['rel_value']
  199. elif self.type == 'slice':
  200. value_field_name = self.value_field_id.name
  201. for f,d in [('total', domain), ('won', won_domain)]:
  202. result = obj.read_group(d, [value_field_name], [])
  203. res[f] = result and result[0][value_field_name] or 0.0
  204. res['domain'] = str(domain)
  205. res['won_domain'] = str(won_domain)
  206. precision = self.precision
  207. total_value = res['total']
  208. res['slice'] = round(100*res['won']/res['total']/precision)*precision if res['total'] else 100
  209. # dummy fields
  210. res['display_mode'] = 'progress'
  211. res['monetary'] = self.value_field_monetary
  212. return res
  213. class mail_wall_widgets_cache(models.Model):
  214. _name = 'mail.wall.widgets.cache'
  215. cache = fields.Text('Cached data')
  216. res_id = fields.Integer('Resource ID')
  217. res_model = fields.Integer('Resource Model')
  218. user_id = fields.Many2one('res.users')
  219. class res_users(models.Model):
  220. _inherit = 'res.users'
  221. @api.v7
  222. def get_serialised_mail_wall_widgets_summary(self, cr, uid, excluded_categories=None, context=None):
  223. return self._get_serialised_mail_wall_widgets_summary(cr, uid, uid, excluded_categories=excluded_categories, context=context)[0]
  224. @api.one
  225. def _get_serialised_mail_wall_widgets_summary(self, excluded_categories=None):
  226. """
  227. [
  228. {
  229. 'id': ...,
  230. 'model': ...,
  231. 'currency': <res.currency id>,
  232. 'data': (depend on model)
  233. },
  234. ]
  235. """
  236. user = self.env.user
  237. res = []
  238. model = 'mail.wall.widgets.widget'
  239. domain = [('group_ids', 'in', user.groups_id.ids), ('active', '=', True)]
  240. for widget in self.env[model].search(domain, order='sequence'):
  241. if widget.cache:
  242. #TODO
  243. continue
  244. res.append({
  245. 'model': model,
  246. 'id': widget.id,
  247. 'currency': user.company_id.currency_id.id,
  248. 'data': widget.get_data(user)[0],
  249. })
  250. return res
  251. #def get_challenge_suggestions(self, cr, uid, context=None):
  252. # """Return the list of challenges suggested to the user"""
  253. # challenge_info = []
  254. # challenge_obj = self.pool.get('mail_wall_widgets.challenge')
  255. # challenge_ids = challenge_obj.search(cr, uid, [('invited_user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context)
  256. # for challenge in challenge_obj.browse(cr, uid, challenge_ids, context=context):
  257. # values = {
  258. # 'id': challenge.id,
  259. # 'name': challenge.name,
  260. # 'description': challenge.description,
  261. # }
  262. # challenge_info.append(values)
  263. # return challenge_info