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.

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