def get(self, **kw): params, data = TinyDict.split(kw) field = params.field.split('/') prefix = '.'.join(field[:-1]) field = field[-1] pctx = TinyForm(**kw).to_python(safe=True) ctx = pctx.chain_get(prefix) or pctx fields = rpc.RPCProxy(params.model).fields_get(False, rpc.session.context) if field not in fields: return {} text = fields[field].get('string') deps = [] for name, attrs in fields.iteritems(): if attrs.get('change_default'): value = ctx.get(name) if value: deps.append((name, name, value, value)) return dict(text=text, deps=str(deps))
def save(self, **kw): params, data = TinyDict.split(kw) error = None error_field = None id = params.id or 0 id = (id > 0) and id or 0 ids = params.ids or [] model = params.parent.model if model != params.model and not params.parent.id: error = _("Parent record doesn't exists...") if error: return dict(error=error) try: proxy = rpc.RPCProxy(model) frm = TinyForm(**kw).to_python() data = {} ctx = context_with_concurrency_info(params.parent.context, params.concurrency_info) source = params.source if source and source != '_terp_list': data = frm.chain_get(source) if data is None: return dict(error_field=error_field, error=error, id=id, ids=str([int(i) for i in ids])) if '__id' in data: data.pop('__id') if 'id' in data: data.pop('id') fld = source.split('/')[-1] data = {fld : [(id and 1, id, data.copy())]} proxy.write([params.parent.id], data, ctx) if not id: all_ids = proxy.read([params.parent.id], [fld])[0][fld] new_ids = [i for i in all_ids if i not in ids] ids = all_ids if new_ids: id = new_ids[0] else: data = frm.copy() if 'id' in data: data.pop('id') if id > 0: proxy.write([id], data, ctx) else: id = proxy.create(data, params.parent.context or {}) ids = [id] + ids except TinyFormError, e: error_field = e.field error = ustr(e)
def save(self, **kw): params, data = TinyDict.split(kw) error = None error_field = None id = params.id or 0 id = (id > 0) and id or 0 ids = params.ids or [] model = params.parent.model if model != params.model and not params.parent.id: error = _("Parent record doesn't exists...") if error: return dict(error=error) try: proxy = rpc.RPCProxy(model) frm = TinyForm(**kw).to_python() data = {} ctx = context_with_concurrency_info(params.parent.context, params.concurrency_info) source = params.source if source and source != '_terp_list': data = frm.chain_get(source) if '__id' in data: data.pop('__id') if 'id' in data: data.pop('id') fld = source.split('/')[-1] data = {fld: [(id and 1, id, data.copy())]} proxy.write([params.parent.id], data, ctx) if not id: all_ids = proxy.read([params.parent.id], [fld])[0][fld] new_ids = [i for i in all_ids if i not in ids] ids = all_ids if new_ids: id = new_ids[0] else: data = frm.copy() if 'id' in data: data.pop('id') if id > 0: proxy.write([id], data, ctx) else: id = proxy.create(data, params.parent.context or {}) ids = [id] + ids except TinyFormError, e: error_field = e.field error = ustr(e)
def eval_domain_and_context(self, **kw): params, data = TinyDict.split(kw) domain = kw.get('_terp_domain', []) context = params.context or {} parent_context = dict(params.parent_context or {}, **rpc.session.context) # filter out default_* and search_default_* from context, # but not when doing a search from the 'search view' (we have to keep parent context) if params.search_mode != 'true': parent_context = self.context_get(params.parent_context) or {} # update active_id in context for links parent_context.update(active_id=params.active_id or False, active_ids=params.active_ids or []) if 'group_by' in parent_context: if isinstance(params.group_by, str): parent_context['group_by'] = cleanup_group_by( params.group_by).split(',') else: parent_context['group_by'] = params.group_by try: ctx = TinyForm(**kw).to_python() pctx = ctx except TinyFormError, e: return dict(error_field=e.field, error=ustr(e))
def eval_domain_and_context(self, **kw): params, data = TinyDict.split(kw) domain = kw.get('_terp_domain', []) context = params.context or {} parent_context = dict(params.parent_context or {}, **rpc.session.context) parent_context = self.context_get(params.parent_context) or {} if 'group_by' in parent_context: if isinstance(params.group_by, str): parent_context['group_by'] = params.group_by.split(',') else: parent_context['group_by'] = params.group_by try: ctx = TinyForm(**kw).to_python() pctx = ctx except TinyFormError, e: return dict(error_field=e.field, error=ustr(e))
def get(self, **kw): params, data = TinyDict.split(kw) error = None error_field = None model = params.model record = kw.get('record') record = eval(record) proxy = rpc.RPCProxy(model) data = {} res = proxy.fields_get(False, rpc.session.context) all_values = {} errors = [] for k, v in record.items(): values = {} for key, val in v.items(): for field in val: fld = { 'value': val[field], 'type': res[field].get('type') } if fld['type'] == 'many2many': fld['type'] = 'char' datas = {field: fld} try: TinyForm(**datas).to_python() except TinyFormError, e: errors.append({e.field: ustr(e)}) except Exception, e: errors.append({field: ustr(e)}) datas['rec'] = field datas['rec_val'] = fld['value'] datas['type'] = fld['type'] values[key] = datas
def eval_domain_filter(self, **kw): all_domains = kw.get('all_domains') custom_domains = kw.get('custom_domain') all_domains = eval(all_domains) domains = all_domains.get('domains') selection_domain = all_domains.get('selection_domain') search_context = all_domains.get('search_context') group_by_ctx = kw.get('group_by_ctx', []) if isinstance(group_by_ctx, str): group_by_ctx = group_by_ctx.split(',') if domains: domains = eval(domains) c = search_context.get('context', {}) v = search_context.get('value') if v and isinstance(v, basestring) and '__' in v: value, operator = v.split('__') v = int(value) ctx = expr_eval(c, {'self':v}) context = rpc.session.context if ctx: ctx.update(context) domain = [] check_domain = all_domains.get('check_domain') if check_domain and isinstance(check_domain, basestring): domain = expr_eval(check_domain, context) or [] search_data = {} model = kw.get('model') proxy = rpc.RPCProxy(model) res = proxy.fields_get(False, context) all_error = [] fld = {} if domains: for field, value in domains.iteritems(): if '/' in field: fieldname, bound = field.split('/') else: fieldname = field bound = '' data = {} fld['type'] = res[fieldname].get('type') if fld['type'] == 'many2many': fld['type'] = 'char' fld['value'] = value data[field] = fld try: frm = TinyForm(**data).to_python() except TinyFormError, e: error_field = e.field error = ustr(e) all_error.append(dict(error=error, error_field=error_field)) continue if bound in ('from', 'to'): if bound == 'from': test = '>=' else: test = '<=' convert_format = openobject.i18n.format.convert_date_format_in_domain([(fieldname, test, value)], res, context) domain.append(convert_format[0]) search_data.setdefault(fieldname, {})[bound] = convert_format[0][2] elif isinstance(value, bool) and value: search_data[field] = 1 elif isinstance(value, int) and not isinstance(value, bool): domain.append((field, '=', value)) search_data[field] = value elif 'selection_' in value: domain.append((field, '=', value.split('selection_')[1])) search_data[field] = value.split('selection_')[1] elif fld['type'] == 'selection': domain.append((field, '=', value)) search_data[field] = value else: if not 'm2o_' in value: operator = 'ilike' if '__' in value: value, operator = value.split('__') value = int(value) domain.append((field, operator, value)) search_data[field] = value else: search_data[field] = value.split('m2o_')[1] if all_error: return dict(all_error=all_error)
def on_change(self, **kw): data = kw.copy() callback = data.pop('_terp_callback') caller = data.pop('_terp_caller') model = data.pop('_terp_model') context = data.pop('_terp_context') try: context = eval(context) # convert to python dict except: context = {} match = re.match('^(.*?)\((.*)\)$', callback) if not match: raise common.error(_('Application Error!'), _('Wrong on_change trigger: %s') % callback) for k, v in data.items(): try: data[k] = eval(v) except: pass result = {} prefix = '' if '/' in caller: prefix = caller.rsplit('/', 1)[0] ctx = TinyForm(**kw).to_python(safe=True) pctx = ctx if prefix: ctx = ctx.chain_get(prefix) if '/' in prefix: pprefix = prefix.rsplit('/', 1)[0] pctx = pctx.chain_get(pprefix) ctx2 = rpc.session.context.copy() ctx2.update(context or {}) ctx['parent'] = pctx ctx['context'] = ctx2 func_name = match.group(1) arg_names = [n.strip() for n in match.group(2).split(',')] ctx_dict = dict(**ctx) args = [tools.expr_eval(arg, ctx_dict) for arg in arg_names] proxy = rpc.RPCProxy(model) ids = ctx.id and [ctx.id] or [] try: response = getattr(proxy, func_name)(ids, *args) except Exception, e: return dict(error=ustr(e))
if data.get(key): kind = data[key].get('type') if key in data and key != 'id': values2[k] = data[key] values2[k]['value'] = v else: values2[k] = {'value': v} if kind == 'float': field = proxy.fields_get([k], ctx2) digit = field[k].get('digits') if digit: digit = digit[1] values2[k]['digit'] = digit or 2 values = TinyForm(**values2).from_python().make_plain() # get name of m2o and reference fields for k, v in values2.items(): kind = v.get('type') relation = v.get('relation') if relation and kind in ('many2one', 'reference') and values.get(k): values[k] = [values[k], tw.many2one.get_name(relation, values[k])] if kind == 'picture': values[k] = generate_url_for_picture(model, k, ctx.id, values[k]) result['value'] = values # convert domains in string to prevent them being converted in JSON
class Form(SecuredController): _cp_path = "/openerp/form" def create_form(self, params, tg_errors=None): if tg_errors: return cherrypy.request.terp_form cherrypy.session['params'] = params params.offset = params.offset or 0 params.limit = params.limit or 50 params.count = params.count or 0 params.view_type = params.view_type or params.view_mode[0] return tw.form_view.ViewForm(params, name="view_form", action="/openerp/form/save") @expose(template="/openerp/controllers/templates/form.mako") def create(self, params, tg_errors=None): params.view_type = params.view_type or params.view_mode[0] if params.view_type == 'tree': params.editable = True form = self.create_form(params, tg_errors) if not tg_errors: try: cherrypy.session.pop('remember_notebooks') except: self.reset_notebooks() editable = form.screen.editable mode = form.screen.view_type id = form.screen.id buttons = TinyDict() # toolbar buttons.new = (not editable or mode == 'tree') and mode != 'diagram' buttons.edit = not editable and (mode == 'form' or mode == 'diagram') buttons.save = editable and mode == 'form' buttons.cancel = editable and mode == 'form' buttons.delete = not editable and mode == 'form' buttons.pager = mode == 'form' or mode == 'diagram' # Pager will visible in edit and non-edit mode in form view. buttons.can_attach = id and mode == 'form' buttons.i18n = not editable and mode == 'form' buttons.show_grid = mode == 'diagram' buttons.create_node = mode == 'diagram' and editable from openerp.widgets import get_registered_views buttons.views = [] for kind, view in get_registered_views(): buttons.views.append( dict(kind=kind, name=view.name, desc=view.desc)) target = getattr(cherrypy.request, '_terp_view_target', None) buttons.toolbar = (target != 'new' and not form.is_dashboard) or mode == 'diagram' pager = None if buttons.pager: pager = tw.pager.Pager(id=form.screen.id, ids=form.screen.ids, offset=form.screen.offset, limit=form.screen.limit, count=form.screen.count, view_type=params.view_type) can_shortcut = self.can_shortcut_create() shortcut_ids = [] if cherrypy.session.get('terp_shortcuts'): for sc in cherrypy.session['terp_shortcuts']: if isinstance(sc['res_id'], tuple): shortcut_ids.append(sc['res_id'][0]) else: shortcut_ids.append(sc['res_id']) title = form.screen.string or '' display_name = {} if params.view_type == 'form': if params.id: if form.screen.view.get( 'fields') and form.screen.view['fields'].get('name'): display_name = { 'field': form.screen.view['fields']['name']['string'], 'value': ustr(form.screen.view['fields']['name']['value']) } title = ustr(display_name['field']) + ':' + ustr( display_name['value']) elif params.view_type == 'diagram': display_name = { 'field': form.screen.view['fields']['name']['string'], 'value': rpc.RPCProxy(params.model).name_get(form.screen.id, rpc.session.context)[0][1] } # For Corporate Intelligence visibility. obj_process = rpc.RPCProxy('ir.model').search( [('model', '=', 'process.process')]) or None tips = params.display_menu_tip if params.view_type == params.view_mode[0] and tips: tips = tips is_dashboard = form.screen.is_dashboard or False return dict(form=form, pager=pager, buttons=buttons, path=self.path, can_shortcut=can_shortcut, shortcut_ids=shortcut_ids, display_name=display_name, title=title, tips=tips, obj_process=obj_process, is_dashboard=is_dashboard) @expose('json', methods=('POST', )) def close_or_disable_tips(self): rpc.RPCProxy('res.users').write(rpc.session.uid, {'menu_tips': False}, rpc.session.context) def _read_form(self, context, count, domain, filter_domain, id, ids, kw, limit, model, offset, search_data, search_domain, source, view_ids, view_mode, view_type, notebook_tab, o2m_edit=False, editable=False): """ Extract parameters for form reading/creation common to both self.edit and self.view """ params, data = TinyDict.split({ '_terp_model': model, '_terp_id': id, '_terp_ids': ids, '_terp_view_ids': view_ids, '_terp_view_mode': view_mode, '_terp_view_type': view_type, '_terp_source': source, '_terp_domain': domain, '_terp_context': context, '_terp_offset': offset, '_terp_limit': limit, '_terp_count': count, '_terp_search_domain': search_domain, '_terp_search_data': search_data, '_terp_filter_domain': filter_domain, '_terp_notebook_tab': notebook_tab }) params.o2m_edit = o2m_edit params.editable = editable params.action_id = kw.get('action_id') if kw.get('default_date'): params.context.update({'default_date': kw['default_date']}) cherrypy.request._terp_view_target = kw.get('target') if params.view_mode and 'form' not in params.view_mode: params.view_type = params.view_mode[-1] if params.view_type == 'tree': params.view_type = 'form' if not params.ids: params.offset = 0 return params @expose() def edit(self, model, id=False, ids=None, view_ids=None, view_mode=['form', 'tree'], view_type='form', source=None, domain=[], context={}, offset=0, limit=50, count=0, search_domain=None, search_data=None, filter_domain=None, o2m_edit=False, **kw): notebook_tab = kw.get('notebook_tab') or 0 params = self._read_form(context, count, domain, filter_domain, id, ids, kw, limit, model, offset, search_data, search_domain, source, view_ids, view_mode, view_type, notebook_tab, o2m_edit=o2m_edit, editable=True) if not params.ids: params.count = 0 # On New O2M if params.source: current = TinyDict() current.id = False params[params.source] = current return self.create(params) @expose() def view(self, model, id, ids=None, view_ids=None, view_mode=['form', 'tree'], view_type='form', source=None, domain=[], context={}, offset=0, limit=50, count=0, search_domain=None, search_data=None, filter_domain=None, **kw): notebook_tab = kw.get('notebook_tab') or 0 params = self._read_form(context, count, domain, filter_domain, id, ids, kw, limit, model, offset, search_data, search_domain, source, view_ids, view_mode, view_type, notebook_tab) if not params.ids: params.count = 1 return self.create(params) @expose() def cancel(self, **kw): params, data = TinyDict.split(kw) if params.button: res = self.button_action(params) if res: return res raise redirect('/') if not params.id and params.ids: params.id = params.ids[0] if params.id and params.editable: raise redirect(self.path + "/view", model=params.model, id=params.id, ids=ustr(params.ids), view_ids=ustr(params.view_ids), view_mode=ustr(params.view_mode), domain=ustr(params.domain), context=ustr(params.context), offset=params.offset, limit=params.limit, count=params.count, search_domain=ustr(params.search_domain), search_data=ustr(params.search_data), filter_domain=ustr(params.filter_domain)) params.view_type = 'tree' return self.create(params) @expose(methods=('POST', )) @validate(form=get_validation_schema) @error_handler(default_error_handler) @exception_handler(default_exception_handler) def save(self, terp_save_only=False, **kw): """Controller method to save/button actions... @param tg_errors: TG special arg, used durring validation @param kw: keyword arguments @return: form view """ params, data = TinyDict.split(kw) # remember the current page (tab) of notebooks cherrypy.session['remember_notebooks'] = True Model = rpc.RPCProxy(params.model) # bypass save, for button action in non-editable view if params.editable: if not params.id: if params.default_o2m: data.update(params.default_o2m) ctx = dict((params.context or {}), **rpc.session.context) params.id = int(Model.create(data, ctx)) params.ids = (params.ids or []) + [params.id] params.count += 1 else: original_data = Model.read(params.id, data.keys()) modified = {} if original_data and isinstance(original_data, dict): for field, original_value in original_data.iteritems(): if isinstance(original_value, tuple): original_data[field] = original_value[0] if field in data and data[field] != original_data[ field]: #When field is many2many at that time following code will be applied if isinstance(data[field], list) and isinstance( data[field][0][2], list): if sorted(data[field][0][2]) != sorted( original_data[field]): modified[field] = data[field] else: modified[field] = data[field] ctx = utils.context_with_concurrency_info( params.context, params.concurrency_info) Model.write([params.id], modified, ctx) else: ctx = utils.context_with_concurrency_info( params.context, params.concurrency_info) Model.write([params.id], data, ctx) tw.ConcurrencyInfo.update( params.model, Model.read([params.id], ['__last_update'], ctx)) cherrypy.request.params = params button = params.button # perform button action if params.button: res = self.button_action(params) if res: return res current = params.chain_get(params.source or '') if current: current.id = None elif not button: params.editable = False if terp_save_only: return dict(params=params, data=data) def get_params(p, f): pp = p.chain_get(f) px = rpc.RPCProxy(p.model) _ids = pp.ids _all = px.read([p.id], [f])[0][f] _new = [i for i in _all if i not in _ids] pp.ids = _all if _new: pp.id = _new[0] return pp if params.source and len(params.source.split("/")) > 1: path = params.source.split("/") p = params for f in path: p = get_params(p, f) return self.create(params) args = { 'model': params.model, 'id': params.id, 'ids': ustr(params.ids), 'view_ids': ustr(params.view_ids), 'view_mode': ustr(params.view_mode), 'domain': ustr(params.domain), 'context': ustr(params.context), 'offset': params.offset, 'limit': params.limit, 'count': params.count, 'search_domain': ustr(params.search_domain), 'search_data': ustr(params.search_data), 'filter_domain': ustr(params.filter_domain), 'notebook_tab': params.notebook_tab } if params.o2m_edit: # hack to avoid creating new record line when editing o2m inline: # by default one2many.mako is going to fetch a new line (.create) # on /edit args['o2m_edit'] = "1" if params.editable or params.source or params.return_edit: raise redirect(self.path + '/edit', source=params.source, **args) raise redirect(self.path + '/view', **args) def button_action_cancel(self, name, params): if name: params.button.btype = "object" params.id = False res = self.button_action(params) if res: return res import actions return actions.close_popup(reload=False) def button_action_save(self, _, params): params.id = False params.button = None def button_action_workflow(self, name, params): model, id, _, _ = self._get_button_infos(params) res = rpc.session.execute('object', 'exec_workflow', model, name, id) if isinstance(res, dict): import actions return actions.execute(res, ids=[id]) params.button = None def button_action_object(self, name, params): model, id, ids, ctx = self._get_button_infos(params) res = rpc.session.execute('object', 'execute', model, name, ids, ctx) # after installation of modules (esp. initial) we may # need values from the global context for some contexts & domains (e.g. # leads) => installer wizards are generally postfixed by '.installer' # so use this characteristic to setup context reloads if model.endswith('.installer'): rpc.session.context_reload() if isinstance(res, dict): import actions return actions.execute(res, ids=[id], context=ctx) params.button = None def button_action_action(self, name, params): model, id, ids, ctx = self._get_button_infos(params) import actions action_id = int(name) action_type = actions.get_action_type(action_id) if action_type == 'ir.actions.wizard': cherrypy.session['wizard_parent_form'] = self.path cherrypy.session[ 'wizard_parent_params'] = params.parent_params or params res = actions.execute_by_id(action_id, type=action_type, model=model, id=id, ids=ids, context=ctx or {}) if res: return res params.button = None BUTTON_ACTIONS_BY_BTYPE = { 'action': button_action_action, 'cancel': button_action_cancel, 'object': button_action_object, 'save': button_action_save, 'workflow': button_action_workflow, } def _get_button_infos(self, params): model = params.button.model id = params.button.id or params.id id = (id or False) and (id) ids = (id or []) and [id] ctx = dict((params.context or {}), **rpc.session.context) ctx.update(params.button.context or {}) return model, id, ids, ctx def button_action(self, params): button_name = openobject.ustr(params.button.name) button_name = button_name.rsplit('/', 1)[-1] btype = params.button.btype try: return self.BUTTON_ACTIONS_BY_BTYPE[btype](self, button_name, params) except KeyError: raise common.warning(_('Invalid button type "%s"') % btype) @expose() def duplicate(self, **kw): params, data = TinyDict.split(kw) id = params.id ctx = params.context model = params.model proxy = rpc.RPCProxy(model) new_id = proxy.copy(id, {}, ctx) if new_id: params.id = new_id params.ids += [int(new_id)] params.count += 1 args = { 'model': params.model, 'id': params.id, 'ids': ustr(params.ids), 'view_ids': ustr(params.view_ids), 'view_mode': ustr(params.view_mode), 'domain': ustr(params.domain), 'context': ustr(params.context), 'offset': params.offset, 'limit': params.limit, 'count': params.count, 'search_domain': ustr(params.search_domain), 'filter_domain': ustr(params.filter_domain) } if new_id: raise redirect(self.path + '/edit', **args) raise redirect(self.path + '/view', **args) @expose() def delete(self, **kw): params, data = TinyDict.split(kw) current = params.chain_get(params.source or '') or params proxy = rpc.RPCProxy(current.model) idx = -1 if current.id: ctx = utils.context_with_concurrency_info(current.context, params.concurrency_info) res = proxy.unlink([current.id], ctx) if current.ids: idx = current.ids.index(current.id) if idx >= 0: current.ids.remove(current.id) params.count -= 1 if not len(current.ids) and params.count > 0: params.offset = params.offset - params.limit current.ids = proxy.search([], params.offset, params.limit, 0, ctx) idx = -1 if idx == len(current.ids): idx = -1 current.id = (current.ids or None) and current.ids[idx] self.reset_notebooks() args = { 'model': params.model, 'id': params.id, 'ids': ustr(params.ids), 'view_ids': ustr(params.view_ids), 'view_mode': ustr(params.view_mode), 'domain': ustr(params.domain), 'context': ustr(params.context), 'offset': params.offset, 'limit': params.limit, 'count': params.count, 'search_domain': ustr(params.search_domain), 'filter_domain': ustr(params.filter_domain) } if not params.id: raise redirect(self.path + '/edit', **args) raise redirect(self.path + '/view', **args) @expose(content_type='application/octet-stream') def save_binary_data(self, _fname='file.dat', **kw): params, data = TinyDict.split(kw) cherrypy.response.headers[ 'Content-Disposition'] = 'attachment; filename="%s"' % _fname if params.datas: form = params.datas['form'] res = form.get(params.field) return base64.decodestring(res) elif params.id: proxy = rpc.RPCProxy(params.model) res = proxy.read([params.id], [params.field], rpc.session.context) return base64.decodestring(res[0][params.field]) else: return base64.decodestring(data[params.field]) @expose() def clear_binary_data(self, **kw): params, data = TinyDict.split(kw) proxy = rpc.RPCProxy(params.model) ctx = utils.context_with_concurrency_info(params.context, params.concurrency_info) if params.fname: proxy.write([params.id], { params.field: False, params.fname: False }, ctx) else: proxy.write([params.id], {params.field: False}, ctx) args = { 'model': params.model, 'id': params.id, 'ids': ustr(params.ids), 'view_ids': ustr(params.view_ids), 'view_mode': ustr(params.view_mode), 'domain': ustr(params.domain), 'context': ustr(params.context), 'offset': params.offset, 'limit': params.limit, 'count': params.count, 'search_domain': ustr(params.search_domain), 'filter_domain': ustr(params.filter_domain) } raise redirect(self.path + '/edit', **args) @expose(content_type='image/png') def binary_image_get_image(self, **kw): model = kw.get('model') field = kw.get('field') id = kw.get('id') proxy = rpc.RPCProxy(model) if id == 'None': # FIXME: doesnt honor the context res = proxy.default_get([field]).get(field, '') else: res = proxy.read([int(id)], [field])[0].get(field) if res: return base64.decodestring(res) else: return open( openobject.paths.addons('openerp', 'static', 'images', 'placeholder.png'), 'rb').read() @expose("json") def binary_image_delete(self, **kw): saved = kw.get('saved') or None model = kw.get('model') id = kw.get('id') if id: id = int(id) field = kw.get('field') if id: proxy = rpc.RPCProxy(model) proxy.write([id], {field: False}) return {} @expose() def b64(self, **kw): #idea from http://dean.edwards.name/weblog/2005/06/base64-ie/ try: qs = cherrypy.request.query_string content_type, data = qs.split(';') data_type, data = data.split(',') assert (data_type == 'base64') cherrypy.response.headers['Content-Type'] = content_type return base64.decodestring(data) except: raise cherrypy.HTTPError(400) # Bad request @expose() @validate(form=get_validation_schema) @error_handler(default_error_handler) @exception_handler(default_exception_handler) def filter(self, **kw): params, data = TinyDict.split(kw) if params.get('_terp_save_current_id'): ctx = dict((params.context or {}), **rpc.session.context) if params.id: rpc.RPCProxy(params.model).write([params.id], data, ctx) else: id = rpc.RPCProxy(params.model).create(data, ctx) params.ids.append(id) params.count += 1 l = params.limit or 50 o = params.offset or 0 c = params.count or 0 id = params.id or False ids = params.ids or [] filter_action = params.filter_action if ids and filter_action == 'FIRST': o = 0 id = ids[0] if ids and filter_action == 'LAST': o = c - c % l id = ids[-1] if ids and filter_action == 'PREV': if id == ids[0]: o -= l elif id in ids: id = ids[ids.index(id) - 1] if ids and filter_action == 'NEXT': if id == ids[-1]: o += l elif id in ids: id = ids[ids.index(id) + 1] elif id is False: o = 0 id = ids[0] if filter_action: # remember the current page (tab) of notebooks cherrypy.session['remember_notebooks'] = True if params.offset != o: domain = params.domain if params.search_domain is not None: domain = params.search_domain data = params.search_data ctx = params.context or {} ctx.update(rpc.session.context.copy()) res = search(params.model, o, l, domain=domain, context=ctx, data=data) o = res['offset'] l = res['limit'] if not c: c = res['count'] params.search_domain = res['search_domain'] params.search_data = res['search_data'] ids = res['ids'] id = False if ids and filter_action in ('FIRST', 'NEXT'): id = ids[0] if ids and filter_action in ('LAST', 'PREV'): id = ids[-1] params.id = id params.ids = ids params.offset = o params.limit = l params.count = c return self.create(params) @expose() def find(self, **kw): kw['_terp_offset'] = None kw['_terp_limit'] = None kw['_terp_search_domain'] = None kw['_terp_search_data'] = None kw['_terp_filter_action'] = 'FIND' return self.filter(**kw) @expose() def first(self, **kw): kw['_terp_filter_action'] = 'FIRST' return self.filter(**kw) @expose() def last(self, **kw): kw['_terp_filter_action'] = 'LAST' return self.filter(**kw) @expose() def previous(self, **kw): if '_terp_source' in kw: return self.previous_o2m(**kw) kw['_terp_filter_action'] = 'PREV' return self.filter(**kw) @expose() def next(self, **kw): if '_terp_source' in kw: return self.next_o2m(**kw) kw['_terp_filter_action'] = 'NEXT' return self.filter(**kw) @expose() @validate(form=get_validation_schema) @error_handler(default_error_handler) @exception_handler(default_exception_handler) def previous_o2m(self, **kw): params, data = TinyDict.split(kw) if params.get('_terp_save_current_id'): ctx = dict((params.context or {}), **rpc.session.context) if params.id: rpc.RPCProxy(params.model).write([params.id], data, ctx) else: id = rpc.RPCProxy(params.model).create(data, ctx) params.ids.append(id) params.count += 1 current = params.chain_get(params.source or '') or params idx = -1 if current.id: # save current record if params.editable: self.save(terp_save_only=True, **kw) idx = current.ids.index(current.id) idx = idx - 1 if idx == len(current.ids): idx = len(current.ids) - 1 if current.ids: current.id = current.ids[idx] return self.create(params) @expose() def next_o2m(self, **kw): params, data = TinyDict.split(kw) c = params.count or 0 current = params.chain_get(params.source or '') or params idx = 0 if current.id: # save current record if params.editable: self.save(terp_save_only=True, **kw) idx = current.ids.index(current.id) idx = idx + 1 if idx == len(current.ids): idx = 0 if current.ids: current.id = current.ids[idx] return self.create(params) @expose() @validate(form=get_validation_schema) def switch(self, **kw): params, data = TinyDict.split(kw) if params.get('_terp_save_current_id'): ctx = dict((params.context or {}), **rpc.session.context) if params.id: rpc.RPCProxy(params.model).write([params.id], data, ctx) else: id = rpc.RPCProxy(params.model).create(data, ctx) params.ids.append(id) params.count += 1 # switch the view params.view_type = params.source_view_type return self.create(params) def do_action(self, name, adds={}, datas={}): params, data = TinyDict.split(datas) model = params.model id = params.id or False ids = params.selection or params.ids or [] if params.view_type == 'form': #TODO: save current record ids = (id or []) and [id] if id and not ids: ids = [id] if len(ids): import actions return actions.execute_by_keyword(name, adds=adds, model=model, id=id, ids=ids, report_type='pdf') else: raise common.message(_("No record selected")) @expose() def report(self, **kw): return self.do_action('client_print_multi', adds={ 'Print Screen': { 'report_name': 'printscreen.list', 'name': _('Print Screen'), 'type': 'ir.actions.report.xml' } }, datas=kw) @expose() def action(self, **kw): params, data = TinyDict.split(kw) context_menu = kw.get('context_menu') or False id = params.id or False ids = params.selection or [] if not ids and id: ids = [id] if not id and ids: id = ids[0] domain = params.domain or [] context = params.context or {} action = {} if data.get('datas'): action = eval(data.get('datas')) type = action.get('type') act_id = params.action if not act_id: return self.do_action('client_action_multi', datas=kw) if type is None: action_type = rpc.RPCProxy('ir.actions.actions').read( act_id, ['type'], context)['type'] tmp_ctx = dict(context) if action_type == 'ir.actions.report.xml': # avoid reading large binary values that we won't even care about tmp_ctx['bin_size'] = True action = rpc.session.execute('object', 'execute', action_type, 'read', act_id, False, tmp_ctx) if domain: if isinstance(domain, basestring): domain = eval(domain) domain.extend(expr_eval(action.get('domain', '[]'), context)) action['domain'] = ustr(domain) action['form_context'] = context or {} import actions return actions.execute(action, model=params.model, id=id, ids=ids, report_type='pdf', context_menu=context_menu) @expose() def dashlet(self, **kw): params, data = TinyDict.split(kw) current = params.chain_get(str(params.source) or '') or params return self.create(current) @expose('json') def on_change(self, **kw): data = kw.copy() callback = data.pop('_terp_callback') caller = data.pop('_terp_caller') model = data.pop('_terp_model') context = data.pop('_terp_context') change_default = False if '_terp_change_default' in data: change_default = data.pop('_terp_change_default') try: context = eval(context) # convert to python dict except: context = {} match = re.match('^(.*?)\((.*)\)$', callback) if not match: raise common.error(_('Application Error'), _('Wrong on_change trigger: %s') % callback) for k, v in data.items(): try: data[k] = eval(v) except: pass result = {} prefix = '' if '/' in caller: prefix = caller.rsplit('/', 1)[0] ctx = TinyForm(**kw).to_python(safe=True) pctx = ctx if prefix: ctx = ctx.chain_get(prefix) if '/' in prefix: pprefix = prefix.rsplit('/', 1)[0] pctx = pctx.chain_get(pprefix) ctx2 = dict(rpc.session.context, **context or {}) ctx['parent'] = pctx ctx['context'] = ctx2 func_name = match.group(1) arg_names = [n.strip() for n in match.group(2).split(',')] args = [utils.expr_eval(arg, ctx) for arg in arg_names] # TODO: If the eval fails in expr_eval (because `arg` does not exist in `ctx`), it returns `{}` # This is a value we don't want, but not sure where that behavior # comes from/is used so in order not to risk breakage throughout # patch it here args = [(False if arg == {} else arg) for arg in args] proxy = rpc.RPCProxy(model) ids = ctx.id and [ctx.id] or [] try: response = getattr(proxy, func_name)(ids, *args) except Exception, e: return dict(error=_ep.render()) if response is False: # response is False when creating new record for inherited view. response = {} if 'value' not in response: response['value'] = {} result.update(response) # apply validators (transform values from python) values = result['value'] values2 = {} for k, v in values.items(): key = ((prefix or '') and prefix + '/') + k kind = data.get(key, {}).get('type', '') if key in data and key != 'id': values2[k] = data[key] values2[k]['value'] = v else: values2[k] = {'value': v} if kind == 'float': field = proxy.fields_get([k], ctx2) digit = field[k].get('digits') if digit: digit = digit[1] values2[k]['digit'] = digit or 2 values = TinyForm(**values2).from_python().make_plain() # get name of m2o and reference fields for k, v in values2.items(): kind = v.get('type') relation = v.get('relation') if relation and kind in ('many2one', 'reference') and values.get(k): values[k] = [ values[k], rpc.name_get(relation, values[k], context) ] result['value'] = values # convert domains in string to prevent them being converted in JSON if 'domain' in result: for k in result['domain']: result['domain'][k] = ustr(result['domain'][k]) if change_default: value = data.get('_terp_value') proxy = rpc.RPCProxy('ir.values') values = proxy.get('default', '%s=%s' % (caller, value), [(model, False)], False, context) for index, fname, value in values: if fname not in result['value']: result['value'][fname] = value return result
def on_change(self, **kw): data = kw.copy() callback = data.pop('_terp_callback') caller = data.pop('_terp_caller') model = data.pop('_terp_model') context = data.pop('_terp_context') change_default = False if '_terp_change_default' in data: change_default = data.pop('_terp_change_default') try: context = eval(context) # convert to python dict except: context = {} match = re.match('^(.*?)\((.*)\)$', callback) if not match: raise common.error(_('Application Error'), _('Wrong on_change trigger: %s') % callback) for k, v in data.items(): try: data[k] = eval(v) except: pass result = {} prefix = '' if '/' in caller: prefix = caller.rsplit('/', 1)[0] ctx = TinyForm(**kw).to_python(safe=True) pctx = ctx if prefix: ctx = ctx.chain_get(prefix) if '/' in prefix: pprefix = prefix.rsplit('/', 1)[0] pctx = pctx.chain_get(pprefix) ctx2 = dict(rpc.session.context, **context or {}) ctx['parent'] = pctx ctx['context'] = ctx2 func_name = match.group(1) arg_names = [n.strip() for n in match.group(2).split(',')] args = [utils.expr_eval(arg, ctx) for arg in arg_names] # TODO: If the eval fails in expr_eval (because `arg` does not exist in `ctx`), it returns `{}` # This is a value we don't want, but not sure where that behavior # comes from/is used so in order not to risk breakage throughout # patch it here args = [(False if arg == {} else arg) for arg in args] proxy = rpc.RPCProxy(model) ids = ctx.id and [ctx.id] or [] try: response = getattr(proxy, func_name)(ids, *args) except Exception, e: return dict(error=_ep.render())
def on_change(self, **kw): data = kw.copy() callback = data.pop('_terp_callback') caller = data.pop('_terp_caller') model = data.pop('_terp_model') context = data.pop('_terp_context') try: context = eval(context) # convert to python dict except: context = {} match = re.match('^(.*?)\((.*)\)$', callback) if not match: raise common.error(_('Application Error'), _('Wrong on_change trigger: %s') % callback) for k, v in data.items(): try: data[k] = eval(v) except: pass result = {} prefix = '' if '/' in caller: prefix = caller.rsplit('/', 1)[0] ctx = TinyForm(**kw).to_python(safe=True) pctx = ctx if prefix: ctx = ctx.chain_get(prefix) if '/' in prefix: pprefix = prefix.rsplit('/', 1)[0] pctx = pctx.chain_get(pprefix) ctx2 = dict(rpc.get_session().context, **context or {}) ctx['parent'] = pctx ctx['context'] = ctx2 func_name = match.group(1) arg_names = [n.strip() for n in match.group(2).split(',')] args = [utils.expr_eval(arg, ctx) for arg in arg_names] # TODO: If the eval fails in expr_eval (because `arg` does not exist in `ctx`), it returns `{}` # This is a value we don't want, but not sure where that behavior # comes from/is used so in order not to risk breakage throughout # patch it here args = [(False if arg == {} else arg) for arg in args] proxy = rpc.RPCProxy(model) ids = ctx.id and [ctx.id] or [] try: response = getattr(proxy, func_name)(ids, *args) except Exception, e: return dict(error=_ep.render())
if data.get(key): kind = data[key].get('type') if key in data and key != 'id': values2[k] = data[key] values2[k]['value'] = v else: values2[k] = {'value': v} if kind == 'float': field = proxy.fields_get([k], ctx2) digit = field[k].get('digits') if digit: digit = digit[1] values2[k]['digit'] = digit or 2 values = TinyForm(**values2).from_python().make_plain() # get name of m2o and reference fields for k, v in values2.items(): kind = v.get('type') relation = v.get('relation') if relation and kind in ('many2one', 'reference') and values.get(k): values[k] = [ values[k], tw.many2one.get_name(relation, values[k]) ] if kind == 'picture': values[k] = generate_url_for_picture(model, k, ctx.id,