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))
Beispiel #2
0
    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))
Beispiel #3
0
    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))
Beispiel #6
0
    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))
Beispiel #7
0
    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
Beispiel #8
0
    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)
Beispiel #9
0
    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))
Beispiel #10
0
            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
Beispiel #11
0
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
Beispiel #12
0
    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())
Beispiel #13
0
    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())
Beispiel #14
0
    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))
Beispiel #15
0
            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,