class Form(TinyInputWidget): """A generic form widget """ template = "/openerp/widgets/form/templates/form.mako" params = ['id'] member_widgets = ['frame', 'concurrency_info'] def __init__(self, prefix, model, view, ids=[], domain=[], context=None, editable=True, readonly=False, nodefault=False, nolinks=1): super(Form, self).__init__(prefix=prefix, model=model, editable=editable, readonly=readonly, nodefault=nodefault) dom = xml.dom.minidom.parseString(view['arch'].encode('utf-8')) root = dom.childNodes[0] attrs = node_attributes(root) fields = view['fields'] self.string = attrs.get('string', '') self.link = attrs.get('link', nolinks) self.model = model self.id = None proxy = rpc.RPCProxy(model) self.context = dict(rpc.session.context, **(context or {})) self.context['bin_size'] = True values = {} defaults = {} try: if ids: lval = proxy.read(ids[:1], fields.keys() + ['__last_update'], self.context) if lval: values = lval[0] self.id = ids[0] ConcurrencyInfo.update(self.model, [values]) elif 'datas' in view: # wizard data for f in fields: if 'value' in fields[f]: values[f] = fields[f]['value'] values.update(view['datas']) elif not self.nodefault: # default defaults = self.get_defaults(fields, domain, self.context) elif 'state' in fields: # if nodefault and state get state only defaults = proxy.default_get(['state'], self.context) elif 'x_state' in fields: # if nodefault and x_state get x_state only (for custom objects) defaults = proxy.default_get(['x_state'], self.context) except Exception,e: raise common.warning(e) if defaults: for k, v in defaults.items(): values.setdefault(k, v) self.state = values.get('state', values.get('x_state')) # store current record values in request object (see, self.parse & O2M default_get_ctx) if not hasattr(cherrypy.request, 'terp_record'): cherrypy.request.terp_record = TinyDict() self.view_fields = [] self.nb_couter = 0 self.frame = self.parse(prefix, dom, fields, values)[0] self.values = [values] self.concurrency_info = ConcurrencyInfo(self.model, [self.id]) # We should generate hidden fields for fields which are not in view, as # the values of such fields might be used during `onchange` for name, attrs in fields.items(): if name not in self.view_fields: kind = attrs.get('type', 'char') if not get_widget(kind): continue attrs['prefix'] = prefix attrs['name'] = name attrs['readonly'] = True # always make them readonly field = self._make_field_widget(attrs, values.get(name)) self.frame.add_hidden(field)
def __init__(self, name, model, view, ids=[], domain=[], context={}, **kw): super(List, self).__init__(name=name, model=model, ids=ids) self.context = context or {} self.domain = domain or [] custom_search_domain = getattr(cherrypy.request, 'custom_search_domain', []) custom_filter_domain = getattr(cherrypy.request, 'custom_filter_domain', []) if name.endswith('/'): self._name = name[:-1] if name != '_terp_list': self.source = self.name.replace('/', '/') or None self.sort_order = kw.get('sort_order', '') self.sort_key = kw.get('sort_key', '') #this Condition is for Dashboard to avoid new, edit, delete operation self.dashboard = 0 self.selectable = kw.get('selectable', 0) self.editable = kw.get('editable', False) self.pageable = kw.get('pageable', True) self.view_mode = kw.get('view_mode', []) self.offset = kw.get('offset', 0) self.limit = kw.get('limit', 0) self.count = kw.get('count', 0) self.link = kw.get('nolinks') self.m2m = kw.get('m2m', 0) self.o2m = kw.get('o2m', 0) self.concurrency_info = None self.selector = None terp_params = getattr(cherrypy.request, 'terp_params', {}) if terp_params: if terp_params.get('_terp_model'): if terp_params[ '_terp_model'] == 'board.board' and terp_params.view_type == 'form': self.dashboard = 1 if terp_params.get('_terp_source'): if (str(terp_params.source) == self.source) or (terp_params.source == '_terp_list' and terp_params.sort_key): self.sort_key = terp_params.sort_key self.sort_order = terp_params.sort_order if self.selectable == 1: self.selector = 'radio' if self.selectable == 2: self.selector = 'checkbox' fields = view['fields'] dom = xml.dom.minidom.parseString(view['arch'].encode('utf-8')) root = dom.childNodes[0] attrs = node_attributes(root) self.string = attrs.get('string', '') search_param = copy.deepcopy(domain) or [] if custom_search_domain: for elem in custom_search_domain: if elem not in self.domain: search_param.append(elem) for elem in custom_filter_domain: if elem not in self.domain: search_param.append(elem) try: self.limit = int(attrs.get('limit')) except: pass self.colors = {} for color_spec in attrs.get('colors', '').split(';'): if color_spec: colour, test = color_spec.split(':') self.colors[colour] = test proxy = rpc.RPCProxy(model) default_data = kw.get('default_data', []) search_text = terp_params.get('_terp_search_text', False) if not self.source: self.source = terp_params.get('_terp_source', None) if not default_data and not self.o2m and not self.m2m: if self.limit > 0: if self.sort_key: ids = proxy.search(search_param, self.offset, self.limit, self.sort_key + ' ' + self.sort_order, context) else: if search_text: if self.source == '_terp_list': ids = proxy.search(search_param, self.offset, self.limit, False, context) else: ids = proxy.search(search_param, self.offset, self.limit, False, context) else: if self.sort_key: ids = proxy.search(search_param, 0, 0, self.sort_key + ' ' + self.sort_order, context) else: ids = proxy.search(search_param, 0, 0, 0, context) if len(ids) < self.limit: if self.offset > 0: self.count = len(ids) + self.offset else: self.count = len(ids) else: self.count = proxy.search_count(search_param, context) if not default_data and self.m2m and not self.view_using_sum_attrs( root): # for many2many we limits 'ids' to be readed only when view is not # using sum, otherwise we need to get all 'ids' to compute sums correctly if ids and self.limit not in (0, -1): ids = self.ids[self.offset:self.offset + self.limit] self.data_dict = {} data = [] if ids and not isinstance(ids, (list, tuple)): ids = [ids] if ids and len(ids) > 0: ctx = rpc.session.context.copy() ctx.update(context) try: data = proxy.read(ids, fields.keys() + ['__last_update'], ctx) except: pass ConcurrencyInfo.update(self.model, data) cherrypy.response.headers.pop('X-Concurrency-Info', None) self.concurrency_info = ConcurrencyInfo(self.model, ids) order_data = [(d['id'], d) for d in data] orderer = dict(zip(ids, count())) ordering = sorted(order_data, key=lambda object: orderer[object[0]]) data = [i[1] for i in ordering] for item in data: self.data_dict[item['id']] = item.copy() if not self.m2m: # update active 'ids' except for many2many which need to get # all known ids for update to work correctly self.ids = ids elif kw.get('default_data', []): data = kw['default_data'] self.values = copy.deepcopy(data) self.headers, self.hiddens, self.data, self.field_total, self.buttons = self.parse( root, fields, data) for k, v in self.field_total.items(): if (len([test[0] for test in self.hiddens if test[0] == k])) <= 0: self.field_total[k][1] = self.do_sum(self.data, k) self.columns = len(self.headers) self.columns += (self.selectable or 0) and 1 self.columns += (self.editable or 0) and 2 self.columns += (self.buttons or 0) and 1 if self.pageable: self.pager = Pager(ids=self.ids, offset=self.offset, limit=self.limit, count=self.count) self.pager._name = self.name # when view is editable, make sure all fields are correctly prefixed # otherwise they may conflict with parent view fields if self.editable: for f, fa in self.headers + self.hiddens: if not isinstance(fa, int): fa['prefix'] = '_terp_listfields' + ( (self.name != '_terp_list' or '') and '/' + self.name) if self.editable and context.get( 'set_editable' ): #Treeview editable by default or set_editable in context attrs['editable'] = "bottom" # make editors if self.editable and attrs.get('editable') in ('top', 'bottom'): for f, fa in self.headers: if not isinstance(fa, int): fa['prefix'] = '_terp_listfields' + ( (self.name != '_terp_list' or '') and '/' + self.name) fa['inline'] = True if fa.get('type') == 'one2many': self.edit_inline = False self.editors = {} break Widget = get_widget(fa.get('type', 'char')) or get_widget('char') self.editors[f] = Widget(**fa) # generate hidden fields if self.editors: for f, fa in self.hiddens: fa['prefix'] = '_terp_listfields' + ( (self.name != '_terp_list' or '') and '/' + self.name) self.editors[f] = form.Hidden(**fa) # limit the data if self.pageable and len(self.data) > self.limit and self.limit != -1: self.data = self.data[self.offset:] self.data = self.data[:min(self.limit, len(self.data))]
def get_events(self, days): proxy = rpc.RPCProxy(self.model) if self.date_stop: # use the correct algorithm: domain = self.domain + [ (self.date_stop, '<=', days[-1].isoformat() + ' 23:59:59'), (self.date_start, '>=', days[0].isoformat() + ' 00:00:00') ] else: # cannot use the correct algorithm, use the old one: first = days[0].month2.prev()[0] #HACK: add prev month domain = self.domain + [ (self.date_start, '>', first.isoformat()), (self.date_start, '<', days[-1].next().isoformat()) ] # convert color values from string to python values if self.color_values and self.color_field in self.fields: try: atr = self.fields[self.color_field] atr['required'] = False wid = get_widget(atr['type'])(**atr) vals = self.color_values[:] for i, v in enumerate(vals): try: vals[i] = wid.validator.to_python(v) except: pass domain.append((self.color_field, "in", vals)) except Exception: pass if self.options and self.options.use_search: domain += self.options.search_domain ctx = rpc.session.context.copy() ctx.update(self.context) order_by = ('sequence' in self.fields or 0) and 'sequence' if self.color_field and self.fields[self.color_field].get( 'relation') and self.color_field not in [ item[0] for item in domain ]: if self.options and self.options.get('_terp_color_filters'): clr_field = self.options['_terp_color_filters'] else: search_limit = 10 need_to_add_the_user_to_the_list_of_users = False if self.context and self.color_field and \ self.context.get('search_default_user_id') and \ self.color_field == 'user_id' and \ self.fields[self.color_field].get('relation') == 'res.users': need_to_add_the_user_to_the_list_of_users = True clr_field = rpc.RPCProxy( self.fields[self.color_field]['relation']).search([], 0, 0, 0, ctx) if need_to_add_the_user_to_the_list_of_users and self.context.get( 'search_default_user_id') not in clr_field: clr_field[search_limit - 1] = self.context.get('search_default_user_id') domain.append((self.color_field, 'in', clr_field)) ids = proxy.search(domain, 0, 0, order_by, ctx) splitIds = [tuple(x.split('-')) for x in ids if isinstance(x, str)] splitIds.sort(key=lambda x: int(x[0])) if splitIds: ids = ["-".join(i) for i in splitIds] result = proxy.read(ids, self.fields.keys() + ['__last_update'], ctx) ConcurrencyInfo.update(self.model, result) self.concurrency_info = ConcurrencyInfo(self.model, ids) colorCount = 1 if self.color_field: for evt in result: key = evt[self.color_field] name = key value = key if isinstance( key, list): # M2O, XMLRPC returns List instead of Tuple evt[self.color_field] = key = tuple(key) if isinstance(key, tuple): # M2O value, name = key if key not in self.colors: colors = choice_colors(colorCount) self.colors[key] = (name, value, colors[-1]) colorCount += 1 events = [] for evt in result: self.convert(evt) events.append(self.get_event_widget(evt)) if self.date_stop: result = events else: # filter out the events which are not in the range result = [] for e in events: if e.dayspan > 0 and days[0] - e.dayspan < e.starts: result.append(e) if e.dayspan == 0 and days[0] <= e.starts: result.append(e) return result