Beispiel #1
0
class ModelRecord(signal_event.signal_event):
    def __init__(self, resource, id, group=None, parent=None, new=False):
        super(ModelRecord, self).__init__()
        self.resource = str(resource)
        self.rpc = RPCProxy(self.resource)
        self.id = id
        self._loaded = False
        self.parent = parent
        self.mgroup = group
        self.value = {}
        self.state_attrs = {}
        self.modified = False
        self.modified_fields = {}
        self._concurrency_check_data = False
        for key, val in self.mgroup.mfields.items():
            self.value[key] = val.create(self)
            if (new and val.attrs['type'] == 'one2many') and (val.attrs.get(
                    'mode', 'tree,form').startswith('form')):
                mod = self.value[key].model_new()
                self.value[key].model_add(mod)

    def __getitem__(self, name):
        return self.mgroup.mfields.get(name, False)

    def __repr__(self):
        return '<ModelRecord %s@%s>' % (self.id, self.resource)

    def is_modified(self):
        return self.modified

    def is_wizard(self):
        return self.mgroup.is_wizard

    def fields_get(self):
        return self.mgroup.mfields

    def _check_load(self):
        if not self._loaded:
            self.reload()
            return True
        return False

    def update_context_with_concurrency_check_data(self, context):
        if self.id and self.is_modified():
            context.setdefault(
                CONCURRENCY_CHECK_FIELD,
                {})["%s,%d" %
                    (self.resource, self.id)] = self._concurrency_check_data
        for name, field in self.mgroup.mfields.items():
            if isinstance(field, O2MField):
                if field.name not in self.value.keys():
                    continue
                v = self.value[field.name]
                from itertools import chain
                for m in chain(v.models, v.models_removed):
                    m.update_context_with_concurrency_check_data(context)

    def get(self,
            get_readonly=True,
            includeid=False,
            check_load=True,
            get_modifiedonly=False):
        if check_load:
            self._check_load()
        value = []
        for name, field in self.mgroup.mfields.items():
            if (get_readonly or not field.get_state_attrs(self).get('readonly', False)) \
                and (not get_modifiedonly or (field.name in self.modified_fields or isinstance(field, O2MField))):
                value.append((name,
                              field.get(self,
                                        readonly=get_readonly,
                                        modified=get_modifiedonly)))
        value = dict(value)
        if includeid:
            value['id'] = self.id
        return value

    def cancel(self):
        self._loaded = False
        self.reload()

    def failed_validation(self):
        invalid_fields = self.rpc.get_invalid_fields()
        for item in invalid_fields:
            if item in self.mgroup.mfields:
                self.mgroup.mfields[item].get_state_attrs(
                    self)['valid'] = False

    def save(self, reload=True):
        self._check_load()

        if not self.id:
            value = self.get(get_readonly=False)
            self.id = self.rpc.create(value, self.context_get())
            if not self.id:
                self.failed_validation()

        else:
            if not self.is_modified():
                return self.id
            value = self.get(get_readonly=False, get_modifiedonly=True)
            context = self.context_get().copy()
            self.update_context_with_concurrency_check_data(context)
            if not self.rpc.write([self.id], value, context):
                self.failed_validation()
                return False
        self._loaded = False
        if reload:
            self.reload()
        else:
            # just reload the CONCURRENCY_CHECK_FIELD
            self._reload([CONCURRENCY_CHECK_FIELD])
        return self.id

    def default_get(self, domain=[], context={}):
        if len(self.mgroup.fields):
            val = self.rpc.default_get(self.mgroup.fields.keys(), context)
            for d in domain:
                if d[0] in self.mgroup.fields:
                    if d[1] == '=':
                        val[d[0]] = d[2]
                    if d[1] == 'in' and len(d[2]) == 1:
                        val[d[0]] = d[2][0]
            self.set_default(val)

    def name_get(self):
        name = self.rpc.name_get([self.id], rpc.session.context)[0]
        return name

    def validate_set(self):
        change = self._check_load()
        for fname in self.mgroup.mfields:
            field = self.mgroup.mfields[fname]
            change = change or not field.get_state_attrs(self).get(
                'valid', True)
            field.get_state_attrs(self)['valid'] = True
        if change:
            self.signal('record-changed')
        self.reload()
        return change

    def validate(self):
        self._check_load()
        ok = True
        mfields_with_errors = []
        for fname, _object in self.mgroup.mfields.iteritems():
            if not self.mgroup.mfields[fname].validate(self):
                print("Not valid field: %s" % (fname))
                mfields_with_errors.append(_object.attrs.get('string', fname))
                ok = False
        if mfields_with_errors:
            common.warning(
                _('Invalid form, correct following fields:\n') +
                '\n'.join(mfields_with_errors))
            return False
        return True

    def _get_invalid_fields(self):
        res = []
        for fname, field in self.mgroup.mfields.items():
            if not field.get_state_attrs(self).get('valid', True):
                res.append((fname, field.attrs['string']))
        return dict(res)

    invalid_fields = property(_get_invalid_fields)

    def context_get(self):
        return self.mgroup.context

    def get_default(self):
        self._check_load()
        value = dict([(name, field.get_default(self))
                      for name, field in self.mgroup.mfields.items()])
        return value

    def set_default(self, val):
        for fieldname, value in val.items():
            if fieldname not in self.mgroup.mfields:
                continue
            self.mgroup.mfields[fieldname].set_default(self, value)
        self._loaded = True
        self.signal('record-changed')

    def set(self, val, modified=False, signal=True):
        later = {}
        for fieldname, value in val.items():
            if fieldname == CONCURRENCY_CHECK_FIELD:
                self._concurrency_check_data = value
            if fieldname not in self.mgroup.mfields:
                continue
            if isinstance(self.mgroup.mfields[fieldname], field.O2MField):
                later[fieldname] = value
                continue
            self.mgroup.mfields[fieldname].set(self, value, modified=modified)
        for fieldname, value in later.items():
            self.mgroup.mfields[fieldname].set(self, value, modified=modified)
        self._loaded = True
        self.modified = modified
        if not self.modified:
            self.modified_fields = {}
        if signal:
            self.signal('record-changed')

    def reload(self):
        return self._reload(self.mgroup.mfields.keys() +
                            [CONCURRENCY_CHECK_FIELD])

    def _reload(self, fields):
        if not self.id:
            return
        c = rpc.session.context.copy()
        c.update(self.context_get())
        c['bin_size'] = True
        res = self.rpc.read([self.id], fields, c)
        if res:
            value = res[0]
            if self.parent:
                self.set(value, signal=False)
            else:
                self.set(value)

    def expr_eval(self, dom, check_load=True):
        if not isinstance(dom, basestring):
            return dom
        if check_load:
            self._check_load()
        d = {}
        for name, mfield in self.mgroup.mfields.items():
            d[name] = mfield.get(self, check_load=check_load)

        d['current_date'] = time.strftime('%Y-%m-%d')
        d['time'] = time
        d['context'] = self.context_get()
        d['active_id'] = self.id
        if self.parent:
            d['parent'] = EvalEnvironment(self.parent)
        val = tools.expr_eval(dom, d)
        return val

    #XXX Shoud use changes of attributes (ro, ...)
    def on_change(self, callback):
        match = re.match('^(.*?)\((.*)\)$', callback)
        if not match:
            raise Exception, 'ERROR: Wrong on_change trigger: %s' % callback
        func_name = match.group(1)
        arg_names = [n.strip() for n in match.group(2).split(',') if n.strip()]
        args = [self.expr_eval(arg) for arg in arg_names]
        ids = self.id and [self.id] or []
        response = getattr(self.rpc, func_name)(ids, *args)
        if response:
            self.set(response.get('value', {}), modified=True)
            if 'domain' in response:
                for fieldname, value in response['domain'].items():
                    if fieldname not in self.mgroup.mfields:
                        continue
                    self.mgroup.mfields[fieldname].attrs['domain'] = value
            warning = response.get('warning', {})
            if warning:
                common.warning(warning['message'], warning['title'])
        self.signal('record-changed')

    def on_change_attrs(self, callback):
        self.signal('attrs-changed')

    def cond_default(self, field, value):
        ir = RPCProxy('ir.values')
        values = ir.get('default', '%s=%s' % (field, value),
                        [(self.resource, False)], False, {})
        data = {}
        for index, fname, value in values:
            data[fname] = value
        self.set_default(data)
Beispiel #2
0
class ModelRecordGroup(signal_event.signal_event):
    def __init__(self,
                 resource,
                 fields,
                 ids=[],
                 parent=None,
                 context={},
                 is_wizard=False,
                 screen=None):
        super(ModelRecordGroup, self).__init__()
        self._readonly = False
        self.parent = parent
        self._context = context
        self._context.update(rpc.session.context)
        self.resource = resource
        self.rpc = RPCProxy(resource)
        self.fields = fields
        self.mfields = {}
        self.mfields_load(fields.keys(), self)
        self.screen = screen

        self.models = ModelList(self)
        self.current_idx = None

        self.load(ids)
        self.models_removed = []
        self.on_write = ''
        self.is_wizard = is_wizard

        self.list_parent = False
        self.list_group = False

    def destroy(self):
        for field in self.mfields.values():
            field.destroy()
        if self.list_group:
            self.list_group.destroy()
        del self.mfields
        del self.fields
        del self.list_group
        del self.models

    def index(self, model):
        return self.models.index(model)

    def mfields_load(self, fkeys, models):
        for fname in fkeys:
            fvalue = models.fields[fname]
            modelfield = field.ModelField(fvalue['type'])
            fvalue['name'] = fname
            models.mfields[fname] = modelfield(models, fvalue)

    def model_move(self, model, position=0):
        self.models.move(model, position)

    def set_sequence(self, get_id, rec_id, field='sequence'):
        seq_ids = []
        index = 0
        for model in self.models:
            seq_ids += [model[field].get(model)]
            index = index + 1

        set_list = list(set(seq_ids))
        if len(seq_ids) != len(set_list):
            set_list.sort()
            repeat = set_list[-1]
            mod_list = seq_ids[len(set_list):]
            for e in range(len(mod_list)):
                repeat = repeat + 1
                mod_list[e] = repeat
            final_list = set_list + mod_list

            index = 0
            for model in self.models:
                model[field].set(model, final_list[index], modified=True)
                if model.id:
                    model.save()
                index = index + 1
        else:
            seq_id = []
            if get_id < rec_id:
                for x in range(get_id, rec_id):
                    seq_id += [self.models[x][field].get(self.models[x])]
                sort_seq = [seq_id[-1]] + seq_id[:-1]
                index = 0
                for x in range(get_id, rec_id):
                    self.models[x][field].set(self.models[x],
                                              sort_seq[index],
                                              modified=True)
                    if self.models[x].id:
                        self.models[x].save()
                    index = index + 1
            else:
                for x in range(rec_id, get_id + 1):
                    seq_id += [self.models[x][field].get(self.models[x])]
                sort_seq = seq_id[1:] + [seq_id[0]]
                index = 0
                for x in range(rec_id, get_id + 1):
                    self.models[x][field].set(self.models[x],
                                              sort_seq[index],
                                              modified=True)
                    if self.models[x].id:
                        self.models[x].save()
                    index = index + 1

    def save(self):
        for model in self.models:
            saved = model.save()
            self.writen(saved)

    def writen(self, edited_id):
        if not self.on_write:
            return
        new_ids = getattr(self.rpc, self.on_write)(edited_id, self.context)
        model_idx = self.models.index(self[edited_id])
        result = False
        for id in new_ids:
            cont = False
            for m in self.models:
                if m.id == id:
                    cont = True
                    m.reload()
            if cont:
                continue
            newmod = ModelRecord(self.resource,
                                 id,
                                 parent=self.parent,
                                 group=self)
            newmod.reload()
            if not result:
                result = newmod
            new_index = min(model_idx, len(self.models) - 1)
            self.model_add(newmod, new_index)
        return result

    def pre_load(self, ids, display=True):
        if not ids:
            return True
        self.models.lock_signal = True
        for id in ids:
            newmod = ModelRecord(self.resource,
                                 id,
                                 parent=self.parent,
                                 group=self)
            self.model_add(newmod)
            #if display:
            #    self.signal('model-changed', newmod)
        self.models.lock_signal = False
        self.signal('record-cleared')
        return True

    def load_for(self, values):
        self.models.lock_signal = True
        for value in values:
            newmod = ModelRecord(self.resource,
                                 value['id'],
                                 parent=self.parent,
                                 group=self)
            newmod.set(value)
            self.models.append(newmod)
            newmod.signal_connect(self, 'record-changed', self._record_changed)
        self.models.lock_signal = False
        self.signal('record-cleared')

    def load(self, ids, display=True, context={}):
        if not ids:
            return True
        if not self.fields:
            return self.pre_load(ids, display)
        c = rpc.session.context.copy()
        c.update(self.context)
        c.update(context)
        c['bin_size'] = True
        values = self.rpc.read(
            ids,
            self.fields.keys() + [rpc.CONCURRENCY_CHECK_FIELD], c)
        if not values:
            return False
        vdict = dict(map(lambda x: (x['id'], x), values))
        v2 = []
        for id in ids:
            if id in vdict:
                v2.append(vdict[id])
        self.load_for(v2)
        self.current_idx = 0
        return True

    def clear(self):
        self.models.clear()
        self.models_removed = []

    def setContext(self, ctx):
        self._context.update(ctx)

    def getContext(self):
        ctx = {}
        ctx.update(self._context)
        #ctx['active_ids'] = [model.id for model in self.models if model.id]
        #if self.current_idx is not None:
        #   ctx['active_id'] = self.models[self.current_idx].id or False
        #else:
        #   ctx['active_id'] = False
        return ctx

    context = property(getContext, setContext)

    def model_add(self, model, position=-1):
        #
        # To be checked
        #
        if not model.mgroup is self:
            fields = {}
            for mf in model.mgroup.fields:
                fields[model.mgroup.fields[mf]
                       ['name']] = model.mgroup.fields[mf]
            self.add_fields(fields, self)
            self.add_fields(self.fields, model.mgroup)
            model.mgroup = self

        if position == -1:
            self.models.append(model)
        else:
            self.models.insert(position, model)
        self.current_idx = position
        model.parent = self.parent
        model.signal_connect(self, 'record-changed', self._record_changed)
        return model

    def model_new(self, default=True, domain=[], context={}):
        newmod = ModelRecord(self.resource,
                             None,
                             group=self,
                             parent=self.parent,
                             new=True)
        newmod.signal_connect(self, 'record-changed', self._record_changed)
        if default:
            ctx = context.copy()
            ctx.update(self.context)
            newmod.default_get(domain, ctx)
        self.signal('model-changed', newmod)
        newmod.list_parent = self.list_parent
        newmod.list_group = self.list_group
        return newmod

    def model_remove(self, model):
        idx = self.models.index(model)
        self.models.remove(model)
        if model.parent:
            model.parent.modified = True
        if self.models:
            self.current_idx = min(idx, len(self.models) - 1)
        else:
            self.current_idx = None

    def _record_changed(self, model, signal_data):
        self.signal('model-changed', model)

    def prev(self):
        if self.models and self.current_idx is not None:
            self.current_idx = (self.current_idx - 1) % len(self.models)
        elif self.models:
            self.current_idx = 0
        else:
            return None
        return self.models[self.current_idx]

    def next(self):
        if self.models and self.current_idx is not None:
            self.current_idx = (self.current_idx + 1) % len(self.models)
        elif self.models:
            self.current_idx = 0
        else:
            return None
        return self.models[self.current_idx]

    def remove(self, model):
        try:
            idx = self.models.index(model)
            if self.models[idx].id:
                self.models_removed.append(self.models[idx])
                self.models[idx].modified = True
            if model.parent:
                model.parent.modified = True
            self.models.remove(self.models[idx])
        except:
            pass

    def add_fields_custom(self, fields, models):
        to_add = []
        for f in fields.keys():
            add_field = True
            if f in models.fields:
                if fields[f].get('widget',
                                 '') == models.fields[f].get('widget', ''):
                    models.fields[f].update(fields[f])
                    add_field = False
                if f in models.mfields and fields[f].get('type',
                                                         '') == 'one2many':
                    add_field = False
            if add_field:
                models.fields[f] = fields[f]
                models.fields[f]['name'] = f
                to_add.append(f)

        self.mfields_load(to_add, models)
        for fname in to_add:
            for m in models.models:
                m.value[fname] = self.mfields[fname].create(m)
        return to_add

    def add_fields(self, fields, models, context=None):
        import time
        ct = time.time()
        if context is None:
            context = {}
        to_add = self.add_fields_custom(fields, models)
        models = models.models
        if not len(models):
            return True

        old = []
        new = []
        for model in models:
            if model.id:
                old.append(model.id)
            else:
                new.append(model)
        ctx = context.copy()
        if len(old) and len(to_add):
            ctx.update(rpc.session.context)
            ctx.update(self.context)

            to_add_normal = [rpc.CONCURRENCY_CHECK_FIELD]
            to_add_binary = []
            for f in to_add:
                if fields[f]['type'] in ('image', 'binary'):
                    to_add_binary.append(f)
                else:
                    to_add_normal.append(f)
            if to_add_normal:
                values = self.rpc.read(old, to_add_normal, ctx)
                if values:
                    for v in values:
                        id = v['id']
                        if 'id' not in to_add:
                            del v['id']
                        self[id].set(v, signal=False)
            if to_add_binary:
                data = {}.fromkeys(to_add_binary, None)
                for m in self.models:
                    m.set(data, signal=False)

        if len(new) and len(to_add):
            ctx.update(self.context)
            values = self.rpc.default_get(to_add, ctx)
            for t in to_add:
                if t not in values:
                    values[t] = False
            for mod in new:
                mod.set_default(values)

    def __iter__(self):
        return iter(self.models)

    def get_by_id(self, id):
        for model in self.models:
            if model.id == id:
                return model

    __getitem__ = get_by_id
Beispiel #3
0
class ModelRecordGroup(signal_event.signal_event):
    def __init__(self, resource, fields, ids=[], parent=None, context={}, is_wizard=False, screen=None):
        super(ModelRecordGroup, self).__init__()
        self._readonly = False
        self.parent = parent
        self._context = context
        self._context.update(rpc.session.context)
        self.resource = resource
        self.rpc = RPCProxy(resource)
        self.fields = fields
        self.mfields = {}
        self.mfields_load(fields.keys(), self)
        self.screen = screen

        self.models = ModelList(self)
        self.current_idx = None

        self.load(ids)
        self.models_removed = []
        self.on_write = ''
        self.is_wizard = is_wizard

        self.list_parent = False
        self.list_group = False

    def destroy(self):
        for field in self.mfields.values():
            field.destroy()
        if self.list_group:
            self.list_group.destroy()
        del self.mfields
        del self.fields
        del self.list_group
        del self.models

    def index(self, model):
        return self.models.index(model)

    def mfields_load(self, fkeys, models):
        for fname in fkeys:
            fvalue = models.fields[fname]
            modelfield = field.ModelField(fvalue['type'])
            fvalue['name'] = fname
            models.mfields[fname] = modelfield(models, fvalue)

    def model_move(self, model, position=0):
        self.models.move(model, position)

    def set_sequence(self, get_id, rec_id, field='sequence'):
        seq_ids = []
        index = 0
        for model in self.models:
             seq_ids += [model[field].get(model)]
             index = index +1

        set_list = list(set(seq_ids))
        if len(seq_ids) != len(set_list):
            set_list.sort()
            repeat = set_list[-1]
            mod_list = seq_ids[len(set_list):]
            for e in range(len(mod_list)):
                repeat = repeat + 1
                mod_list[e]= repeat
            final_list = set_list + mod_list

            index = 0
            for model in self.models:
                model[field].set(model, final_list[index], modified=True)
                if model.id:
                    model.save()
                index = index +1
        else:
            seq_id = []
            if get_id < rec_id:
                for x in range(get_id, rec_id):
                        seq_id += [self.models[x][field].get(self.models[x])]
                sort_seq = [seq_id[-1]] + seq_id[:-1]
                index = 0
                for x in range(get_id, rec_id):
                    self.models[x][field].set(self.models[x], sort_seq[index], modified=True)
                    if self.models[x].id:
                        self.models[x].save()
                    index = index +1
            else:
                for x in range(rec_id,get_id+1):
                    seq_id  += [self.models[x][field].get(self.models[x])]
                sort_seq = seq_id[1:] + [seq_id[0]]
                index = 0
                for x in range(rec_id,get_id+1):
                    self.models[x][field].set(self.models[x], sort_seq[index], modified=True)
                    if self.models[x].id:
                        self.models[x].save()
                    index = index +1


    def save(self):
        for model in self.models:
            saved = model.save()
            self.writen(saved)

    def writen(self, edited_id):
        if not self.on_write:
            return
        new_ids = getattr(self.rpc, self.on_write)(edited_id, self.context)
        model_idx = self.models.index(self[edited_id])
        result = False
        for id in new_ids:
            cont = False
            for m in self.models:
                if m.id == id:
                    cont = True
                    m.reload()
            if cont:
                continue
            newmod = ModelRecord(self.resource, id, parent=self.parent, group=self)
            newmod.reload()
            if not result:
                result = newmod
            new_index = min(model_idx, len(self.models)-1)
            self.model_add(newmod, new_index)
        return result

    def pre_load(self, ids, display=True):
        if not ids:
            return True
        self.models.lock_signal = True
        for id in ids:
            newmod = ModelRecord(self.resource, id, parent=self.parent, group=self)
            self.model_add(newmod)
            #if display:
            #    self.signal('model-changed', newmod)
        self.models.lock_signal = False
        self.signal('record-cleared')
        return True

    def load_for(self, values):
        self.models.lock_signal = True
        for value in values:
            newmod = ModelRecord(self.resource, value['id'], parent=self.parent, group=self)
            newmod.set(value)
            self.models.append(newmod)
            newmod.signal_connect(self, 'record-changed', self._record_changed)
        self.models.lock_signal = False
        self.signal('record-cleared')

    def load(self, ids, display=True, context={}):
        if not ids:
            return True
        if not self.fields:
            return self.pre_load(ids, display)
        c = rpc.session.context.copy()
        c.update(self.context)
        c.update(context)
        c['bin_size'] = True
        values = self.rpc.read(ids, self.fields.keys() + [rpc.CONCURRENCY_CHECK_FIELD], c)
        if not values:
            return False
        vdict = dict(map(lambda x: (x['id'], x), values))
        v2 = []
        for id in ids:
            if id in vdict:
                v2.append(vdict[id])
        self.load_for(v2)
        self.current_idx = 0
        return True

    def clear(self):
        self.models.clear()
        self.models_removed = []

    def setContext(self, ctx):
        self._context.update(ctx)

    def getContext(self):
        ctx = {}
        ctx.update(self._context)
        #ctx['active_ids'] = [model.id for model in self.models if model.id]
        #if self.current_idx is not None:
        #   ctx['active_id'] = self.models[self.current_idx].id or False
        #else:
        #   ctx['active_id'] = False
        return ctx
    context = property(getContext, setContext)

    def model_add(self, model, position=-1):
        #
        # To be checked
        #
        if not model.mgroup is self:
            fields = {}
            for mf in model.mgroup.fields:
                fields[model.mgroup.fields[mf]['name']] = model.mgroup.fields[mf]
            self.add_fields(fields, self)
            self.add_fields(self.fields, model.mgroup)
            model.mgroup = self

        if position==-1:
            self.models.append(model)
        else:
            self.models.insert(position, model)
        self.current_idx = position
        model.parent = self.parent
        model.signal_connect(self, 'record-changed', self._record_changed)
        return model

    def model_new(self, default=True, domain=[], context={}):
        newmod = ModelRecord(self.resource, None, group=self,
                parent=self.parent, new=True)
        newmod.signal_connect(self, 'record-changed', self._record_changed)
        if default:
            ctx=context.copy()
            ctx.update(self.context)
            newmod.default_get(domain, ctx)
        self.signal('model-changed', newmod)
        newmod.list_parent = self.list_parent
        newmod.list_group = self.list_group
        return newmod

    def model_remove(self, model):
        idx = self.models.index(model)
        self.models.remove(model)
        if model.parent:
            model.parent.modified = True
        if self.models:
            self.current_idx = min(idx, len(self.models)-1)
        else:
            self.current_idx = None

    def _record_changed(self, model, signal_data):
        self.signal('model-changed', model)

    def prev(self):
        if self.models and self.current_idx is not None:
            self.current_idx = (self.current_idx - 1) % len(self.models)
        elif self.models:
            self.current_idx = 0
        else:
            return None
        return self.models[self.current_idx]

    def next(self):
        if self.models and self.current_idx is not None:
            self.current_idx = (self.current_idx + 1) % len(self.models)
        elif self.models:
            self.current_idx = 0
        else:
            return None
        return self.models[self.current_idx]

    def remove(self, model):
        try:
            idx = self.models.index(model)
            if self.models[idx].id:
                self.models_removed.append(self.models[idx])
                self.models[idx].modified = True
            if model.parent:
                model.parent.modified = True
            self.models.remove(self.models[idx])
        except:
            pass

    def add_fields_custom(self, fields, models):
        to_add = []
        for f in fields.keys():
            add_field = True
            if f in models.fields:
                if fields[f].get('widget','') == models.fields[f].get('widget',''):
                    models.fields[f].update(fields[f])
                    add_field = False
                if f in models.mfields and fields[f].get('type','') == 'one2many':
                    add_field = False
            if add_field:
                models.fields[f] = fields[f]
                models.fields[f]['name'] = f
                to_add.append(f)

        self.mfields_load(to_add, models)
        for fname in to_add:
            for m in models.models:
                m.value[fname] = self.mfields[fname].create(m)
        return to_add

    def add_fields(self, fields, models, context=None):
        import time
        ct = time.time()
        if context is None:
            context = {}
        to_add = self.add_fields_custom(fields, models)
        models = models.models
        if not len(models):
            return True

        old = []
        new = []
        for model in models:
            if model.id:
                old.append(model.id)
            else:
                new.append(model)
        ctx = context.copy()
        if len(old) and len(to_add):
            ctx.update(rpc.session.context)
            ctx.update(self.context)

            to_add_normal = [rpc.CONCURRENCY_CHECK_FIELD]
            to_add_binary = []
            for f in to_add:
                if fields[f]['type'] in ('image', 'binary'):
                    to_add_binary.append(f)
                else:
                    to_add_normal.append(f)
            if to_add_normal:
                values = self.rpc.read(old, to_add_normal, ctx)
                if values:
                    for v in values:
                        id = v['id']
                        if 'id' not in to_add:
                            del v['id']
                        self[id].set(v, signal=False)
            if to_add_binary:
                data = {}.fromkeys(to_add_binary, None)
                for m in self.models:
                    m.set(data, signal=False)

        if len(new) and len(to_add):
            if self.parent and self.screen:
                ctx.update(self.parent.expr_eval(self.screen.default_get))
            ctx.update(self.context)
            values = self.rpc.default_get(to_add, ctx)
            for t in to_add:
                if t not in values:
                    values[t] = False
            for mod in new:
                mod.set_default(values)
                if values:
                    mod.modified = True

    def __iter__(self):
        return iter(self.models)

    def get_by_id(self, id):
        for model in self.models:
            if model.id == id:
                return model

    __getitem__ = get_by_id
Beispiel #4
0
class ModelRecord(signal_event.signal_event):
    def __init__(self, resource, id, group=None, parent=None, new=False ):
        super(ModelRecord, self).__init__()
        self.resource = str(resource)
        self.rpc = RPCProxy(self.resource)
        self.id = id
        self._loaded = False
        self.parent = parent
        self.mgroup = group
        self.value = {}
        self.state_attrs = {}
        self.modified = False
        self.modified_fields = {}
        self._concurrency_check_data = False
        for key,val in self.mgroup.mfields.items():
            self.value[key] = val.create(self)
            if (new and val.attrs['type']=='one2many') and (val.attrs.get('mode','tree,form').startswith('form')):
                mod = self.value[key].model_new()
                self.value[key].model_add(mod)

    def __getitem__(self, name):
        return self.mgroup.mfields.get(name, False)

    def __repr__(self):
        return '<ModelRecord %s@%s>' % (self.id, self.resource)

    def is_modified(self):
        return self.modified

    def is_wizard(self):
        return self.mgroup.is_wizard

    def fields_get(self):
        return self.mgroup.mfields

    def _check_load(self):
        if not self._loaded:
            self.reload()
            return True
        return False
    
    def update_context_with_concurrency_check_data(self, context):
        if self.id and self.is_modified():
            context.setdefault(CONCURRENCY_CHECK_FIELD, {})["%s,%d" % (self.resource, self.id)] = self._concurrency_check_data
        for name, field in self.mgroup.mfields.items():
            if isinstance(field, O2MField):
                if field.name not in self.value.keys():
                    continue
                v = self.value[field.name] 
                from itertools import chain
                for m in chain(v.models, v.models_removed):
                    m.update_context_with_concurrency_check_data(context)

    def get(self, get_readonly=True, includeid=False, check_load=True, get_modifiedonly=False):
        if check_load:
            self._check_load()
        value = []
        for name, field in self.mgroup.mfields.items():
            if (get_readonly or not field.get_state_attrs(self).get('readonly', False)) \
                and (not get_modifiedonly or (field.name in self.modified_fields or isinstance(field, O2MField))):
                    value.append((name, field.get(self, readonly=get_readonly,
                        modified=get_modifiedonly)))
        value = dict(value)
        if includeid:
            value['id'] = self.id
        return value

    def cancel(self):
        self._loaded = False
        self.reload()

    def failed_validation(self):
        invalid_fields = self.rpc.get_invalid_fields()
        for item in invalid_fields:
           if item in self.mgroup.mfields:
               self.mgroup.mfields[item].get_state_attrs(self)['valid'] = False

    def save(self, reload=True):
        self._check_load()

        if not self.id:
            value = self.get(get_readonly=False)
            self.id = self.rpc.create(value, self.context_get())
            if not self.id:
                self.failed_validation()

        else:
            if not self.is_modified():
                return self.id
            value = self.get(get_readonly=False, get_modifiedonly=True)
            context = self.context_get().copy()
            self.update_context_with_concurrency_check_data(context)
            if not self.rpc.write([self.id], value, context):
                self.failed_validation()
                return False
        self._loaded = False
        if reload:
            self.reload()
        else:
            # just reload the CONCURRENCY_CHECK_FIELD
            self._reload([CONCURRENCY_CHECK_FIELD])
        return self.id

    def default_get(self, domain=[], context={}):
        if len(self.mgroup.fields):
            val = self.rpc.default_get(self.mgroup.fields.keys(), context)
            for d in domain:
                if d[0] in self.mgroup.fields:
                    if d[1] == '=':
                        val[d[0]] = d[2]
                    if d[1] == 'in' and len(d[2]) == 1:
                        val[d[0]] = d[2][0]
            self.set_default(val)

    def name_get(self):
        name = self.rpc.name_get([self.id], rpc.session.context)[0]
        return name

    def validate_set(self):
        change = self._check_load()
        for fname in self.mgroup.mfields:
            field = self.mgroup.mfields[fname]
            change = change or not field.get_state_attrs(self).get('valid', True)
            field.get_state_attrs(self)['valid'] = True
        if change:
            self.signal('record-changed')
        self.reload()
        return change

    def validate(self):
        self._check_load()
        ok = True
        for fname in self.mgroup.mfields:
            if not self.mgroup.mfields[fname].validate(self):
                ok = False
        return ok

    def _get_invalid_fields(self):
        res = []
        for fname, field in self.mgroup.mfields.items():
            if not field.get_state_attrs(self).get('valid', True):
                res.append((fname, field.attrs['string']))
        return dict(res)
    invalid_fields = property(_get_invalid_fields)

    def context_get(self):
        return self.mgroup.context

    def get_default(self):
        self._check_load()
        value = dict([(name, field.get_default(self))
                      for name, field in self.mgroup.mfields.items()])
        return value

    def set_default(self, val):
        for fieldname, value in val.items():
            if fieldname not in self.mgroup.mfields:
                continue
            self.mgroup.mfields[fieldname].set_default(self, value)
        self._loaded = True
        self.signal('record-changed')

    def set(self, val, modified=False, signal=True):
        later={}
        for fieldname, value in val.items():
            if fieldname == CONCURRENCY_CHECK_FIELD:
                self._concurrency_check_data = value
            if fieldname not in self.mgroup.mfields:
                continue
            if isinstance(self.mgroup.mfields[fieldname], field.O2MField):
                later[fieldname]=value
                continue
            self.mgroup.mfields[fieldname].set(self, value, modified=modified)
        for fieldname, value in later.items():
            self.mgroup.mfields[fieldname].set(self, value, modified=modified)
        self._loaded = True
        self.modified = modified
        if not self.modified:
            self.modified_fields = {}
        if signal:
            self.signal('record-changed')
    
    def reload(self):
        return self._reload(self.mgroup.mfields.keys() + [CONCURRENCY_CHECK_FIELD])

    def _reload(self, fields):
        if not self.id:
            return
        c = rpc.session.context.copy()
        c.update(self.context_get())
        c['bin_size'] = True
        res = self.rpc.read([self.id], fields, c)
        if res:
            value = res[0]
            if self.parent:
                self.set(value, signal=False)
            else:
                self.set(value)

    def expr_eval(self, dom, check_load=True):
        if not isinstance(dom, basestring):
            return dom
        if check_load:
            self._check_load()
        d = {}
        for name, mfield in self.mgroup.mfields.items():
            d[name] = mfield.get(self, check_load=check_load)

        d['current_date'] = time.strftime('%Y-%m-%d')
        d['time'] = time
        d['context'] = self.context_get()
        d['active_id'] = self.id
        if self.parent:
            d['parent'] = EvalEnvironment(self.parent)
        val = tools.expr_eval(dom, d)
        return val

    #XXX Shoud use changes of attributes (ro, ...)
    def on_change(self, callback):
        match = re.match('^(.*?)\((.*)\)$', callback)
        if not match:
            raise Exception, 'ERROR: Wrong on_change trigger: %s' % callback
        func_name = match.group(1)
        arg_names = [n.strip() for n in match.group(2).split(',') if n.strip()]
        args = [self.expr_eval(arg) for arg in arg_names]
        ids = self.id and [self.id] or []
        response = getattr(self.rpc, func_name)(ids, *args)
        if response:
            self.set(response.get('value', {}), modified=True)
            if 'domain' in response:
                for fieldname, value in response['domain'].items():
                    if fieldname not in self.mgroup.mfields:
                        continue
                    self.mgroup.mfields[fieldname].attrs['domain'] = value
            warning=response.get('warning',{})
            if warning:
                common.warning(warning['message'], warning['title'])
        self.signal('record-changed')

    def on_change_attrs(self, callback):
        self.signal('attrs-changed')

    def cond_default(self, field, value):
        ir = RPCProxy('ir.values')
        values = ir.get('default', '%s=%s' % (field, value),
                        [(self.resource, False)], False, {})
        data = {}
        for index, fname, value in values:
            data[fname] = value
        self.set_default(data)