This commit is contained in:
Cédric Krier committed 2013-09-03 11:22:15 +02:00
commit 7c9f5ffa89
10 files changed
+254 -270

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
* Remove the default order on MPTT
* Add grouped attribute to data tag
* Store selection tree state
* Add order to Action Window
* Add factor on number fields
+3 -2
View File
@@ -110,8 +110,9 @@ Here is the list of the tags:
* ``tryton``: The main tag of the xml
* ``data``: Define a set of data inside the file. It can have the
attributes ``noupdate`` to prevent the framework to update the records
and ``skiptest`` to prevent import of data when running tests.
attributes ``noupdate`` to prevent the framework to update the records,
``skiptest`` to prevent import of data when running tests and ``grouped``
to create records at the end with a grouped call.
* ``record``: Create a record of the model defined by the attribute
``model`` in the database. The ``id`` attribute can be used to refer to
+43 -19
View File
@@ -8,6 +8,9 @@ import logging
import traceback
import sys
import re
from itertools import izip
from collections import defaultdict
from trytond.version import VERSION
from trytond.tools import safe_eval
from trytond.transaction import Transaction
@@ -384,6 +387,8 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
self.fs2db = Fs2bdAccessor(self.ModelData, pool)
self.to_delete = self.populate_to_delete()
self.noupdate = None
self.grouped = None
self.grouped_creations = defaultdict(dict)
self.skip_data = False
# Tag handlders are used to delegate the processing
@@ -430,6 +435,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
elif name == "data":
self.noupdate = bool(int(attributes.get("noupdate", '0')))
self.grouped = bool(int(attributes.get('grouped', 0)))
if self.pool.test and \
bool(int(attributes.get("skiptest", '0'))):
self.skip_data = True
@@ -452,6 +458,11 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
def endElement(self, name):
if name == 'data' and self.grouped:
for model, values in self.grouped_creations.iteritems():
self.create_records(model, values.values(), values.keys())
self.grouped_creations.clear()
# Closing tag found, if we are in a delegation the handler
# know what to do:
if self.taghandler and not self.skip_data:
@@ -675,30 +686,43 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
self.fs2db.reset_browsercord(module, Model.__name__, [record.id])
else:
# this record is new, create it in the db:
with Transaction().set_context(module=module, language='en_US'):
record, = Model.create([values])
if self.grouped:
self.grouped_creations[model][fs_id] = values
else:
self.create_records(model, [values], [fs_id])
# re-read it: this ensure that we store the real value
# in the model_data table:
record = Model(record.id)
def create_records(self, model, vlist, fs_ids):
Model = self.pool.get(model)
with Transaction().set_context(module=self.module, language='en_US'):
records = Model.create(vlist)
mdata_values = []
for record, values, fs_id in izip(records, vlist, fs_ids):
for key in values:
values[key] = self._clean_value(key, record)
mdata, = self.ModelData.create([{
'fs_id': fs_id,
'model': model,
'module': module,
'db_id': record.id,
'values': str(values),
'noupdate': self.noupdate,
}])
mdata_values.append({
'fs_id': fs_id,
'model': model,
'module': self.module,
'db_id': record.id,
'values': str(values),
'noupdate': self.noupdate,
})
# update fs2db:
self.fs2db.set(module, fs_id, {
"db_id": record.id, "model": model,
"id": mdata.id, "values": str(values)})
self.fs2db.reset_browsercord(module, model, [record.id])
models_data = self.ModelData.create(mdata_values)
for record, values, fs_id, mdata in izip(
records, vlist, fs_ids, models_data):
self.fs2db.set(self.module, fs_id, {
'db_id': record.id,
'model': model,
'id': mdata.id,
'values': str(values),
})
self.fs2db.reset_browsercord(self.module, model,
[r.id for r in records])
def post_import(pool, module, to_delete):
+10 -1
View File
@@ -204,26 +204,35 @@ class Lang(ModelSQL, ModelView):
@classmethod
def create(cls, vlist):
pool = Pool()
Translation = pool.get('ir.translation')
# Clear cache
cls._lang_cache.clear()
return super(Lang, cls).create(vlist)
languages = super(Lang, cls).create(vlist)
Translation._get_language_cache.clear()
return languages
@classmethod
def write(cls, langs, vals):
pool = Pool()
Translation = pool.get('ir.translation')
# Clear cache
cls._lang_cache.clear()
super(Lang, cls).write(langs, vals)
Translation._get_language_cache.clear()
@classmethod
def delete(cls, langs):
pool = Pool()
Config = pool.get('ir.configuration')
Translation = pool.get('ir.translation')
for lang in langs:
if lang.code == Config.get_language():
cls.raise_user_error('delete_default')
# Clear cache
cls._lang_cache.clear()
super(Lang, cls).delete(langs)
Translation._get_language_cache.clear()
@staticmethod
def _group(lang, s, monetary=None):
+10
View File
@@ -3,6 +3,7 @@
import datetime
import re
import heapq
from collections import defaultdict
from ..model import ModelView, ModelSQL, fields
from ..report import Report
@@ -368,6 +369,10 @@ class ModelAccess(ModelSQL, ModelView):
@classmethod
def get_access(cls, models):
'Return access for models'
# root user above constraint
if Transaction().user == 0:
return defaultdict(lambda: defaultdict(lambda: True))
pool = Pool()
Model = pool.get('ir.model')
UserGroup = pool.get('res.user-res.group')
@@ -503,6 +508,11 @@ class ModelFieldAccess(ModelSQL, ModelView):
@classmethod
def get_access(cls, models):
'Return fields access for models'
# root user above constraint
if Transaction().user == 0:
return defaultdict(lambda: defaultdict(
lambda: defaultdict(lambda: True)))
pool = Pool()
Model = pool.get('ir.model')
ModelField = pool.get('ir.model.field')
+94 -54
View File
@@ -16,6 +16,7 @@ except ImportError:
from md5 import md5
from functools import reduce
from lxml import etree
from itertools import izip
from ..model import ModelView, ModelSQL, fields
from ..wizard import Wizard, StateView, StateTransition, StateAction, \
@@ -71,6 +72,7 @@ class Translation(ModelSQL, ModelView):
searcher='search_model')
_translation_cache = Cache('ir.translation', size_limit=10240,
context=False)
_get_language_cache = Cache('ir.translation')
@classmethod
def __setup__(cls):
@@ -153,11 +155,15 @@ class Translation(ModelSQL, ModelView):
@classmethod
def get_language(cls):
result = cls._get_language_cache.get(None)
if result is not None:
return result
pool = Pool()
Lang = pool.get('ir.lang')
langs = Lang.search([])
res = [(lang.code, lang.name) for lang in langs]
return res
result = [(lang.code, lang.name) for lang in langs]
cls._get_language_cache.set(None, result)
return result
@classmethod
def get_src_md5(cls, src):
@@ -249,12 +255,21 @@ class Translation(ModelSQL, ModelView):
return translations
@classmethod
def set_ids(cls, name, ttype, lang, ids, value):
def set_ids(cls, name, ttype, lang, ids, values):
"Set translation for each id"
pool = Pool()
ModelFields = pool.get('ir.model.field')
Model = pool.get('ir.model')
Config = pool.get('ir.configuration')
cursor = Transaction().cursor
in_max = cursor.IN_MAX
if len(ids) > in_max:
for i in range(0, len(ids), in_max):
sub_ids = ids[i:i + in_max]
sub_values = values[i:i + in_max]
cls.set_ids(name, ttype, lang, sub_ids, sub_values)
return
model_name, field_name = name.split(',')
if model_name in ('ir.model.field', 'ir.model'):
@@ -269,74 +284,99 @@ class Translation(ModelSQL, ModelView):
ttype = 'model'
with Transaction().set_context(language='en_US'):
records = Model.browse(ids)
for record in records:
def get_name(record):
if ttype in ('field', 'help'):
name = record.model.model + ',' + record.name
return record.model.model + ',' + record.name
else:
name = record.model + ',' + field_name
translation2 = cls.search([
('lang', '=', lang),
('type', '=', ttype),
('name', '=', name),
])
with Transaction().set_user(0):
if not translation2:
cls.create([{
'name': name,
'lang': lang,
'type': ttype,
'src': getattr(record, field_name),
'value': value,
'fuzzy': False,
}])
else:
cls.write(translation2, {
return record.model + ',' + field_name
translations = {}
for translation in cls.search([
('lang', '=', lang),
('type', '=', ttype),
('name', 'in', [get_name(r) for r in records]),
]):
translations[translation.name] = translation
to_create = []
for record, value in izip(records, values):
translation = translations.get(get_name(record))
if not translation:
to_create.append({
'name': name,
'lang': lang,
'type': ttype,
'src': getattr(record, field_name),
'value': value,
'fuzzy': False,
})
return len(ids)
else:
with Transaction().set_user(0):
cls.write([translation], {
'src': getattr(record, field_name),
'value': value,
'fuzzy': False,
})
if to_create:
with Transaction().set_user(0):
cls.create(to_create)
return
Model = pool.get(model_name)
with Transaction().set_context(language=Config.get_language()):
records = Model.browse(ids)
for record in records:
translation2 = cls.search([
('lang', '=', lang),
('type', '=', ttype),
('name', '=', name),
('res_id', '=', record.id),
])
with Transaction().set_user(0):
if not translation2:
cls.create([{
'name': name,
'lang': lang,
'type': ttype,
'res_id': record.id,
'value': value,
'src': getattr(record, field_name),
'fuzzy': False,
}])
else:
cls.write(translation2, {
translations = {}
for translation in cls.search([
('lang', '=', lang),
('type', '=', ttype),
('name', '=', name),
('res_id', 'in', ids),
]):
translations[translation.res_id] = translation
other_translations = {}
if (lang == Config.get_language()
and Transaction().context.get('fuzzy_translation', True)):
for translation in cls.search([
('lang', '!=', lang),
('type', '=', ttype),
('name', '=', name),
('res_id', 'in', ids),
]):
other_translations.setdefault(translation.res_id, []
).append(translation)
to_create = []
for record, value in izip(records, values):
translation = translations.get(record.id)
if not translation:
to_create.append({
'name': name,
'lang': lang,
'type': ttype,
'res_id': record.id,
'value': value,
'src': getattr(record, field_name),
'fuzzy': False,
})
if (lang == Config.get_language()
and Transaction().context.get('fuzzy_translation',
True)):
other_langs = cls.search([
('lang', '!=', lang),
('type', '=', ttype),
('name', '=', name),
('res_id', '=', record.id),
])
else:
with Transaction().set_user(0):
cls.write([translation], {
'value': value,
'src': getattr(record, field_name),
'fuzzy': False,
})
other_langs = other_translations.get(record.id)
if other_langs:
cls.write(other_langs, {
'src': getattr(record, field_name),
'fuzzy': True,
})
return len(ids)
if to_create:
with Transaction().set_user(0):
cls.create(to_create)
@classmethod
def delete_ids(cls, model, ttype, ids):
+77 -134
View File
@@ -223,6 +223,7 @@ class ModelSQL(ModelStorage):
super(ModelSQL, cls).create(vlist)
cursor = Transaction().cursor
pool = Pool()
Translation = pool.get('ir.translation')
if cls.table_query():
return False
@@ -349,16 +350,21 @@ class ModelSQL(ModelStorage):
create_records = Transaction().create_records.setdefault(cls.__name__,
set()).update(new_ids)
translation_values = {}
for values, new_id in izip(vlist, new_ids):
for fname, value in values.iteritems():
field = cls._fields[fname]
if getattr(field, 'translate', False):
pool.get('ir.translation').set_ids(
cls.__name__ + ',' + fname, 'model',
Transaction().language, [new_id], value)
translation_values.setdefault(cls.__name__ + ',' + fname,
{})[new_id] = value
if hasattr(field, 'set'):
field.set([new_id], cls, fname, value)
if translation_values:
for name, translations in translation_values.iteritems():
Translation.set_ids(name, 'model', Transaction().language,
translations.keys(), translations.values())
if cls._history:
columns = ['"' + str(x) + '"' for x in cls._fields
if not hasattr(cls._fields[x], 'set')]
@@ -375,17 +381,8 @@ class ModelSQL(ModelStorage):
records = cls.browse(new_ids)
cls._validate(records)
# Check for Modified Preorder Tree Traversal
for k in cls._fields:
field = cls._fields[k]
if (isinstance(field, fields.Many2One)
and field.model_name == cls.__name__
and field.left and field.right):
if len(new_ids) == 1:
cls._update_tree(new_ids[0], k, field.left, field.right)
else:
with Transaction().set_user(0):
cls._rebuild_tree(k, False, 0)
field_names = cls._fields.keys()
cls._update_mptt(field_names, [new_ids] * len(field_names))
cls.trigger_create(records)
return records
@@ -801,8 +798,8 @@ class ModelSQL(ModelStorage):
for field in direct:
if getattr(cls._fields[field], 'translate', False):
Translation.set_ids(
cls.__name__ + ',' + field, 'model',
Transaction().language, ids, values[field])
cls.__name__ + ',' + field, 'model',
Transaction().language, ids, [values[field]] * len(ids))
# call the 'set' method of fields
for field in upd_todo:
@@ -820,21 +817,8 @@ class ModelSQL(ModelStorage):
cls._validate(records)
# Check for Modified Preorder Tree Traversal
for k in cls._fields:
field = cls._fields[k]
if isinstance(field, fields.Many2One) \
and field.model_name == cls.__name__ \
and field.left and field.right:
if field.left in values or field.right in values:
raise Exception('ValidateError',
'You can not update fields: "%s", "%s"' %
(field.left, field.right))
if len(ids) == 1:
cls._update_tree(ids[0], k, field.left, field.right)
else:
with Transaction().set_user(0):
cls._rebuild_tree(k, False, 0)
field_names = cls._fields.keys()
cls._update_mptt(field_names, [ids] * len(field_names), values)
cls.trigger_write(trigger_eligibles)
@@ -1011,13 +995,7 @@ class ModelSQL(ModelStorage):
'(id, write_uid, write_date) VALUES (%s, %s, %s)',
(obj_id, Transaction().user, datetime.datetime.now()))
for k in tree_ids.keys():
field = cls._fields[k]
if len(tree_ids[k]) == 1:
cls._update_tree(tree_ids[k][0], k, field.left, field.right)
else:
with Transaction().set_user(0):
cls._rebuild_tree(k, False, 0)
cls._update_mptt(tree_ids.keys(), tree_ids.values())
@classmethod
def search(cls, domain, offset=0, limit=None, order=None, count=False,
@@ -1888,6 +1866,31 @@ class ModelSQL(ModelStorage):
raise Exception('Error', 'Wrong field name (%s) for %s in order!' %
(field, cls.__name__))
@classmethod
def _update_mptt(cls, field_names, list_ids, values=None):
cursor = Transaction().cursor
count = None
for field_name, ids in zip(field_names, list_ids):
field = cls._fields[field_name]
if (isinstance(field, fields.Many2One)
and field.model_name == cls.__name__
and field.left and field.right):
if (values is not None
and (field.left in values or field.right in values)):
raise Exception('ValidateError',
'You can not update fields: "%s", "%s"' %
(field.left, field.right))
if count is None:
cursor.execute('SELECT COUNT(1) FROM "' + cls._table + '"')
count, = cursor.fetchone()
if len(ids) < count / 4:
for id_ in ids:
cls._update_tree(id_, field_name,
field.left, field.right)
else:
with Transaction().set_user(0):
cls._rebuild_tree(field_name, None, 0)
@classmethod
def _rebuild_tree(cls, parent, parent_id, left):
'''
@@ -1896,10 +1899,9 @@ class ModelSQL(ModelStorage):
cursor = Transaction().cursor
right = left + 1
with Transaction().set_user(0):
childs = cls.search([
(parent, '=', parent_id),
])
childs = cls.search([
(parent, '=', parent_id),
], order=[])
for child in childs:
right = cls._rebuild_tree(parent, child.id, right)
@@ -1914,35 +1916,36 @@ class ModelSQL(ModelStorage):
return right + 1
@classmethod
def _update_tree(cls, object_id, field_name, left, right):
def _update_tree(cls, record_id, field_name, left, right):
'''
Update left, right values for the tree.
Remarks:
- the value (right - left - 1) / 2 will not give
the number of children node
- the order of the tree respects the default _order
'''
cursor = Transaction().cursor
cursor.execute('SELECT "' + left + '", "' + right + '" '
cursor.execute('SELECT "' + left + '", "' + right + '", '
'"' + field_name + '" '
'FROM "' + cls._table + '" '
'WHERE id = %s', (object_id,))
'WHERE id = %s', (record_id,))
fetchone = cursor.fetchone()
if not fetchone:
return
old_left, old_right = fetchone
if old_left == old_right:
old_left, old_right, parent_id = fetchone
if old_left == old_right == 0:
cursor.execute('SELECT MAX("' + right + '") '
'FROM "' + cls._table + '" '
'WHERE "' + field_name + '" IS NULL')
old_left, = cursor.fetchone()
old_left += 1
old_right = old_left + 1
cursor.execute('UPDATE "' + cls._table + '" '
'SET "' + right + '" = "' + right + '" + 1 '
'WHERE id = %s', (object_id,))
old_right += 1
'SET "' + left + '" = %s, "' + right + '" = %s '
'WHERE id = %s', (old_left, old_right, record_id))
size = old_right - old_left + 1
parent_right = 1
cursor.execute('SELECT "' + field_name + '" '
'FROM "' + cls._table + '" '
'WHERE id = %s', (object_id,))
parent_id = cursor.fetchone()[0] or False
if parent_id:
cursor.execute('SELECT "' + right + '" '
'FROM "' + cls._table + '" '
@@ -1956,85 +1959,25 @@ class ModelSQL(ModelStorage):
if fetchone:
parent_right = fetchone[0] + 1
cursor.execute('SELECT id FROM "' + cls._table + '" '
'WHERE "' + left + '" >= %s AND "' + right + '" <= %s',
(old_left, old_right))
child_ids = [x[0] for x in cursor.fetchall()]
if len(child_ids) > cursor.IN_MAX:
with Transaction().set_user(0):
return cls._rebuild_tree(field_name, False, 0)
red_child_sql, red_child_ids = reduce_ids('id', child_ids)
# ids for left update
cursor.execute('SELECT id FROM "' + cls._table + '" '
'WHERE "' + left + '" >= %s '
'AND NOT ' + red_child_sql,
[parent_right] + red_child_ids)
left_ids = [x[0] for x in cursor.fetchall()]
# ids for right update
cursor.execute('SELECT id FROM "' + cls._table + '" '
'WHERE "' + right + '" >= %s '
'AND NOT ' + red_child_sql,
[parent_right] + red_child_ids)
right_ids = [x[0] for x in cursor.fetchall()]
if left_ids:
for i in range(0, len(left_ids), cursor.IN_MAX):
sub_ids = left_ids[i:i + cursor.IN_MAX]
red_sub_sql, red_sub_ids = reduce_ids('id', sub_ids)
cursor.execute('UPDATE "' + cls._table + '" '
'SET "' + left + '" = "' + left + '" + '
+ str(old_right - old_left + 1) + ' '
'WHERE ' + red_sub_sql, red_sub_ids)
if right_ids:
for i in range(0, len(right_ids), cursor.IN_MAX):
sub_ids = right_ids[i:i + cursor.IN_MAX]
red_sub_sql, red_sub_ids = reduce_ids('id', sub_ids)
cursor.execute('UPDATE "' + cls._table + '" '
'SET "' + right + '" = "' + right + '" + '
+ str(old_right - old_left + 1) + ' '
'WHERE ' + red_sub_sql, red_sub_ids)
cursor.execute('UPDATE "' + cls._table + '" '
'SET "' + left + '" = "' + left + '" + '
+ str(parent_right - old_left) + ', '
'"' + right + '" = "' + right + '" + '
+ str(parent_right - old_left) + ' '
'WHERE ' + red_child_sql, red_child_ids)
# Use root user to by-pass rules
with contextlib.nested(Transaction().set_user(0),
Transaction().set_context(active_test=False)):
brother_ids = map(int, cls.search([
(field_name, '=', parent_id),
]))
if brother_ids[-1] != object_id:
next_id = brother_ids[brother_ids.index(object_id) + 1]
cursor.execute('SELECT "' + left + '" '
'FROM "' + cls._table + '" '
'WHERE id = %s', (next_id,))
next_left = cursor.fetchone()[0]
cursor.execute('SELECT "' + left + '" '
'FROM "' + cls._table + '" '
'WHERE id = %s', (object_id,))
current_left = cursor.fetchone()[0]
cursor.execute('UPDATE "' + cls._table + '" '
'SET "' + left + '" = "' + left + '" + '
+ str(old_right - old_left + 1) + ', '
'"' + right + '" = "' + right + '" + '
+ str(old_right - old_left + 1) + ' '
'WHERE "' + left + '" >= %s AND "' + right + '" <= %s',
(next_left, current_left))
cursor.execute('UPDATE "' + cls._table + '" '
'SET "' + left + '" = "' + left + '" - '
+ str(current_left - next_left) + ', '
'"' + right + '" = "' + right + '" - '
+ str(current_left - next_left) + ' '
'WHERE ' + red_child_sql, red_child_ids)
'SET "' + left + '" = "' + left + '" + %s '
'WHERE "' + left + '" >= %s', (size, parent_right))
cursor.execute('UPDATE "' + cls._table + '" '
'SET "' + right + '" = "' + right + '" + %s '
'WHERE "' + right + '" >= %s', (size, parent_right))
if old_left < parent_right:
params = (parent_right - old_left,
parent_right - old_left,
old_left, old_right)
else:
params = (parent_right - old_left - size,
parent_right - old_left - size,
old_left + size, old_right + size)
cursor.execute('UPDATE "' + cls._table + '" '
'SET "' + left + '" = "' + left + '" + %s, '
'"' + right + '" = "' + right + '" + %s '
'WHERE "' + left + '" >= %s '
'AND "' + right + '" <= %s', params)
@classmethod
def validate(cls, records):
-8
View File
@@ -12,9 +12,6 @@ class MPTT(ModelSQL, ModelView):
'Modified Preorder Tree Traversal'
__name__ = 'test.mptt'
name = fields.Char('Name', required=True)
sequence = fields.Integer('Sequence',
order_field='(%(table)s.sequence IS NULL) %(order)s, '
'%(table)s.sequence %(order)s')
parent = fields.Many2One('test.mptt', "Parent", select=True,
left="left", right="right")
left = fields.Integer('Left', required=True, select=True)
@@ -22,11 +19,6 @@ class MPTT(ModelSQL, ModelView):
childs = fields.One2Many('test.mptt', 'parent', 'Children')
active = fields.Boolean('Active')
@classmethod
def __setup__(cls):
super(MPTT, cls).__setup__()
cls._order.insert(0, ('sequence', 'ASC'))
@classmethod
def validate(cls, record):
super(MPTT, cls).validate(record)
+13 -52
View File
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import sys
import unittest
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
install_module
@@ -17,12 +18,10 @@ class MPTTTestCase(unittest.TestCase):
install_module('test')
self.mptt = POOL.get('test.mptt')
def CheckTree(self, parent_id=False, left=0, right=0):
def CheckTree(self, parent_id=False, left=-1, right=sys.maxint):
childs = self.mptt.search([
('parent', '=', parent_id),
])
child_index = dict((x.id, i) for i, x in enumerate(childs))
childs.sort(key=lambda x: child_index[x.id])
], order=[('left', 'ASC')])
for child in childs:
assert child.left > left, \
'%s: left %d <= parent left %d' % \
@@ -30,21 +29,21 @@ class MPTTTestCase(unittest.TestCase):
assert child.left < child.right, \
'%s: left %d >= right %d' % \
(child, child.left, child.right)
assert right == 0 or child.right < right, \
assert child.right < right, \
'%s: right %d >= parent right %d' % \
(child, child.right, right)
self.CheckTree(child.id, left=child.left,
right=child.right)
next_left = 0
next_left = -1
for child in childs:
assert child.left > next_left, \
'%s: left %d <= next left %d' % \
(child, child.left, next_left)
next_left = child.right
childs.reverse()
previous_right = 0
previous_right = sys.maxint
for child in childs:
assert previous_right == 0 or child.right < previous_right, \
assert child.right < previous_right, \
'%s: right %d >= previous right %d' \
% (child, child.right, previous_right)
previous_right = child.left
@@ -65,62 +64,28 @@ class MPTTTestCase(unittest.TestCase):
for record in records:
self.ReParent(record)
def ReOrder(self, parent=None):
records = self.mptt.search([
('parent', '=', parent),
])
if not records:
return
i = len(records)
for record in records:
record.sequence = i
record.save()
i -= 1
i = 0
for record in records:
record.sequence = i
record.save()
i += 1
for record in records:
self.ReOrder(record)
records = self.mptt.search([])
self.mptt.write(records, {
'sequence': 0,
})
def test0010create(self):
'''
Create tree.
'''
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
new_records = [None]
new_records = [None, None, None]
for j in range(3):
parent_records = new_records
new_records = []
k = 0
for parent_record in parent_records:
for i in range(3):
new_records += self.mptt.create([{
'name': 'Test %d %d %d' % (j, k, i),
'parent': (parent_record.id
if parent_record else None),
}])
new_records += self.mptt.create([{
'name': 'Test %d %d %d' % (j, k, i),
'parent': (parent_record.id
if parent_record else None),
} for i in range(3)])
k += 1
self.CheckTree()
transaction.cursor.commit()
def test0020reorder(self):
'''
Re-order.
'''
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
self.ReOrder()
transaction.cursor.rollback()
def test0030reparent(self):
'''
Re-parent.
@@ -141,8 +106,6 @@ class MPTTTestCase(unittest.TestCase):
self.CheckTree()
self.ReParent()
self.CheckTree()
self.ReOrder()
self.CheckTree()
transaction.cursor.rollback()
@@ -164,8 +127,6 @@ class MPTTTestCase(unittest.TestCase):
})
self.ReParent()
self.CheckTree()
self.ReOrder()
self.CheckTree()
transaction.cursor.rollback()
+2
View File
@@ -5,6 +5,8 @@ attlist.tryton &= empty
data = element data { attlist.data, (record | menuitem)* }
attlist.data &=
[ a:defaultValue = "0" ] attribute noupdate { "0" | "1" }?
attlist.data &=
[ a:defaultValue = "0" ] attribute grouped { "0" | "1" }?
record = element record { attlist.record, field* }
attlist.record &= attribute model { text }
attlist.record &= attribute id { text }