from openerp.osv import osv,fields as old_fields from openerp import api, models, fields, tools from openerp.tools.safe_eval import safe_eval from openerp.addons.email_template.email_template import mako_template_env import copy from openerp.tools.translate import _ from datetime import date, datetime, timedelta from openerp.tools import DEFAULT_SERVER_DATE_FORMAT from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT class mail_wall_widgets_widget(models.Model): _name = 'mail.wall.widgets.widget' _order = "sequence, id" _columns = { 'name': old_fields.char('Name', required=True, translate=True), 'type': old_fields.selection(string='Type', selection=[ ('list', 'List'), ('funnel', 'Funnel'), ('slice', 'Slice'), #('', ''), #('', ''), #('', ''), #('', ''), ], help=''' Slice - use "domain" for total and "won_domain" for target '''), 'description': old_fields.text('Description', translate=True), '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"), 'model_id': old_fields.many2one('ir.model', string='Model', help='The model object for the field to evaluate'), '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), 'limit': old_fields.integer('Limit', help='Limit count of records to show'), 'order': old_fields.char('Order', help='Order of records to show'), 'value_field_id': old_fields.many2one('ir.model.fields', string='Value field', help='The field containing the value of record'), 'stage_field_id': old_fields.many2one('ir.model.fields', string='Stage field', help='Field to split records in funnel. It can be selection type or many2one (the later should have "sequence" field)'), #'stage_field_domain': old_fields.many2one('ir.model.fields', # string='Stage field domain', # help='(for many2one stage_field_id) Domain to find stage objects'), 'won_domain': old_fields.char('Won domain', help='Domain to find won objects'), 'field_date_id': old_fields.many2one('ir.model.fields', string='Date Field', help='The date to use for the time period evaluated'), 'start_date': old_fields.date('Start Date'), 'end_date': old_fields.date('End Date'), # no start and end = always active 'content': old_fields.char('Line template', help='Mako template to show content'), 'value_field_monetary': old_fields.boolean('Value is monetary'), 'cache': old_fields.boolean('Cache'), 'active': old_fields.boolean('Active'), 'sequence': old_fields.integer('Sequence', help='Sequence number for ordering'), } 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) agenda = fields.Boolean('Agenda', help='Split records by date: overdue, today, tomorrow, later') _defaults = { 'active': True, 'cache': False, 'limit': None, 'order': None, } @api.one def get_data(self, user): domain = safe_eval(self.domain, {'user': user}) won_domain = safe_eval(self.won_domain or '[]', {'user': user}) field_date_name = self.field_date_id and self.field_date_id.name if self.start_date and field_date_name: domain.append((field_date_name, '>=', self.start_date)) if self.end_date and field_date_name: domain.append((field_date_name, '<=', self.end_date)) res = { 'name': self.name, 'type': self.type, 'model': self.model_id.model, 'domain': str(domain), 'precision': self.precision, } obj = self.env[self.model_id.model] if self.type == 'list': total_count = obj.search_count(domain) groups = [{'test': lambda r: True}] if self.agenda: today = date.today() tomorrow = today + timedelta(days=1) def r2date(r): d = getattr(r, field_date_name) d = datetime.strptime(d, self.field_date_id.ttype=='date' and DEFAULT_SERVER_DATE_FORMAT or DEFAULT_SERVER_DATETIME_FORMAT) d = d.date() return d groups = [ { 'label': _('Overdue'), 'class': 'overdue', 'test': lambda r: r2date(r) < today, 'mandatory': False, }, { 'label': _('Today'), 'class': 'today', 'test': lambda r: r2date(r) == today, 'mandatory': True, }, { 'label': _('Tomorrow'), 'class': 'tomorrow', 'test': lambda r: r2date(r) == tomorrow, 'mandatory': False, }, { 'label': _('Later'), 'class': 'later', 'test': lambda r: r2date(r) > tomorrow, 'mandatory': False, }, ] for g in groups: g['lines'] = [] res.update({ 'more': self.limit and self.limit < total_count, 'total_count': total_count, 'agenda': self.agenda, 'groups': groups, }) for r in obj.search(domain, limit=self.limit, order=self.order): mako = mako_template_env.from_string(tools.ustr(self.content)) content = mako.render({'record':r}) r_json = { 'id': r.id, #'fields': dict( (f,getattr(r,f)) for f in fields), 'display_mode': 'progress', 'state': 'inprogress', 'completeness': 0, 'name': content, 'description': '', } if self.value_field_id: r_json['current'] = getattr(r, self.value_field_id.name) if self.value_field_monetary: r_json['monetary'] = 1 for g in groups: if g['test'](r): g['lines'].append(r_json) break for g in groups: del g['test'] elif self.type == 'funnel': stage_ids = [] # [key] for group in obj.read_group(domain, [], [self.stage_field_id.name]): key = group[self.stage_field_id.name] if isinstance(key, (list, tuple)): key = key[0] stage_ids.append(key) stages = [] # [{'name':Name, 'id': key}] if self.stage_field_id.ttype == 'selection': d = dict (self.stage_field_id.selection) stages = [ {'id':id, 'name':d[id]} for id in stage_ids ] else: # many2one stage_model = self.stage_field_id.relation for r in self.env[stage_model].browse(stage_ids): stages.append({'id': r.id, 'name':r.name_get()[0][1]}) value_field_name = self.value_field_id.name for stage in stages: d = copy.copy(domain) d.append( (self.stage_field_id.name, '=', stage['id']) ) result = obj.read_group(d, [value_field_name], []) stage['closed_value'] = result and result[0][value_field_name] or 0.0 stage['domain'] = str(d) # won value d = domain + won_domain result = obj.read_group(domain, [value_field_name], []) won = {'name': _('Won'), 'id':'__won__', 'closed_value': result and result[0][value_field_name] or 0.0 } stages.append(won) cur = 0 for stage in reversed(stages): cur += stage['closed_value'] stage['abs_value'] = cur total_value = stages[0]['abs_value'] precision = self.precision for s in stages: s['rel_value'] = round(100*s['abs_value']/total_value/precision)*precision if total_value else 100 # dummy fields s['display_mode'] = 'progress' s['monetary'] = 1 res['stages'] = stages res['won'] = won res['conversion_rate'] = stages[-1]['rel_value'] elif self.type == 'slice': value_field_name = self.value_field_id.name for f,d in [('total', domain), ('won', won_domain)]: result = obj.read_group(d, [value_field_name], []) res[f] = result and result[0][value_field_name] or 0.0 res['domain'] = str(domain) res['won_domain'] = str(won_domain) precision = self.precision total_value = res['total'] res['slice'] = round(100*res['won']/res['total']/precision)*precision if res['total'] else 100 # dummy fields res['display_mode'] = 'progress' res['monetary'] = self.value_field_monetary return res class mail_wall_widgets_cache(models.Model): _name = 'mail.wall.widgets.cache' cache = fields.Text('Cached data') res_id = fields.Integer('Resource ID') res_model = fields.Integer('Resource Model') user_id = fields.Many2one('res.users') class res_users(models.Model): _inherit = 'res.users' @api.v7 def get_serialised_mail_wall_widgets_summary(self, cr, uid, excluded_categories=None, context=None): return self._get_serialised_mail_wall_widgets_summary(cr, uid, uid, excluded_categories=excluded_categories, context=context)[0] @api.one def _get_serialised_mail_wall_widgets_summary(self, excluded_categories=None): """ [ { 'id': ..., 'model': ..., 'currency': , 'data': (depend on model) }, ] """ user = self.env.user res = [] model = 'mail.wall.widgets.widget' domain = [('group_ids', 'in', user.groups_id.ids), ('active', '=', True)] for widget in self.env[model].search(domain, order='sequence'): if widget.cache: #TODO continue res.append({ 'model': model, 'id': widget.id, 'currency': user.company_id.currency_id.id, 'data': widget.get_data(user)[0], }) return res #def get_challenge_suggestions(self, cr, uid, context=None): # """Return the list of challenges suggested to the user""" # challenge_info = [] # challenge_obj = self.pool.get('mail_wall_widgets.challenge') # challenge_ids = challenge_obj.search(cr, uid, [('invited_user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context) # for challenge in challenge_obj.browse(cr, uid, challenge_ids, context=context): # values = { # 'id': challenge.id, # 'name': challenge.name, # 'description': challenge.description, # } # challenge_info.append(values) # return challenge_info