Compare commits
9 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a84e3ed8ba | ||
![]() |
4876b06421 | ||
![]() |
619a4e9ed6 | ||
![]() |
559a5d0656 | ||
![]() |
2fdee39611 | ||
![]() |
4df6284257 | ||
![]() |
0aa9df2f1d | ||
![]() |
dadcfb618f | ||
![]() |
603a9d7477 |
11 changed files with 262 additions and 18 deletions
12
README.rst
12
README.rst
|
@ -14,6 +14,18 @@ Requires
|
||||||
Changes
|
Changes
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
*6.0.3 - 31.08.2022*
|
||||||
|
|
||||||
|
- updt: checks, sorting
|
||||||
|
|
||||||
|
*6.0.2 - 25.08.2022*
|
||||||
|
|
||||||
|
- add: split-booking
|
||||||
|
|
||||||
|
*6.0.1 - 23.08.2022*
|
||||||
|
|
||||||
|
- works
|
||||||
|
|
||||||
*6.0.0 - 05.08.2022*
|
*6.0.0 - 05.08.2022*
|
||||||
|
|
||||||
- init
|
- init
|
||||||
|
|
19
book.py
19
book.py
|
@ -76,14 +76,16 @@ class Book(Workflow, ModelSQL, ModelView):
|
||||||
),
|
),
|
||||||
}, depends=DEPENDS+['lines'])
|
}, depends=DEPENDS+['lines'])
|
||||||
start_balance = fields.Numeric(string='Initial Amount', required=True,
|
start_balance = fields.Numeric(string='Initial Amount', required=True,
|
||||||
|
digits=(16, Eval('currency_digits', 2)),
|
||||||
states={
|
states={
|
||||||
'readonly': Or(
|
'readonly': Or(
|
||||||
STATES['readonly'],
|
STATES['readonly'],
|
||||||
Bool(Eval('lines')),
|
Bool(Eval('lines')),
|
||||||
),
|
),
|
||||||
}, depends=DEPENDS+['lines'])
|
}, depends=DEPENDS+['lines', 'currency_digits'])
|
||||||
balance = fields.Function(fields.Numeric(string='Balance', readonly=True),
|
balance = fields.Function(fields.Numeric(string='Balance', readonly=True,
|
||||||
'on_change_with_balance')
|
digits=(16, Eval('currency_digits', 2)),
|
||||||
|
depends=['currency_digits']), 'on_change_with_balance')
|
||||||
currency = fields.Many2One(string='Currency', required=True,
|
currency = fields.Many2One(string='Currency', required=True,
|
||||||
model_name='currency.currency',
|
model_name='currency.currency',
|
||||||
states={
|
states={
|
||||||
|
@ -92,6 +94,8 @@ class Book(Workflow, ModelSQL, ModelView):
|
||||||
Bool(Eval('lines', [])),
|
Bool(Eval('lines', [])),
|
||||||
),
|
),
|
||||||
}, depends=DEPENDS+['lines'])
|
}, depends=DEPENDS+['lines'])
|
||||||
|
currency_digits = fields.Function(fields.Integer(string='Currency Digits',
|
||||||
|
readonly=True), 'on_change_with_currency_digits')
|
||||||
state = fields.Selection(string='State', required=True,
|
state = fields.Selection(string='State', required=True,
|
||||||
readonly=True, selection=sel_state_book)
|
readonly=True, selection=sel_state_book)
|
||||||
state_string = state.translated('state')
|
state_string = state.translated('state')
|
||||||
|
@ -196,6 +200,15 @@ class Book(Workflow, ModelSQL, ModelView):
|
||||||
'state': self.state_string,
|
'state': self.state_string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@fields.depends('currency')
|
||||||
|
def on_change_with_currency_digits(self, name=None):
|
||||||
|
""" currency of cashbook
|
||||||
|
"""
|
||||||
|
if self.currency:
|
||||||
|
return self.currency.digits
|
||||||
|
else:
|
||||||
|
return 2
|
||||||
|
|
||||||
@fields.depends('id', 'start_balance')
|
@fields.depends('id', 'start_balance')
|
||||||
def on_change_with_balance(self, name=None):
|
def on_change_with_balance(self, name=None):
|
||||||
""" compute balance
|
""" compute balance
|
||||||
|
|
91
category.py
91
category.py
|
@ -3,12 +3,46 @@
|
||||||
# The COPYRIGHT file at the top level of this repository contains the
|
# The COPYRIGHT file at the top level of this repository contains the
|
||||||
# full copyright notices and license terms.
|
# full copyright notices and license terms.
|
||||||
|
|
||||||
from trytond.model import ModelView, ModelSQL, fields, Unique, tree, sequence_ordered
|
from trytond.model import ModelView, ModelSQL, fields, Unique, Exclude, tree
|
||||||
from trytond.transaction import Transaction
|
from trytond.transaction import Transaction
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.pyson import Eval, If, Bool
|
from trytond.pyson import Eval, If, Bool
|
||||||
from trytond.exceptions import UserError
|
from trytond.exceptions import UserError
|
||||||
from trytond.i18n import gettext
|
from trytond.i18n import gettext
|
||||||
|
from sql.operators import Equal
|
||||||
|
from sql.functions import Function
|
||||||
|
from sql import With, Literal
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayApppend(Function):
|
||||||
|
""" sql: array_append
|
||||||
|
"""
|
||||||
|
__slots__ = ()
|
||||||
|
_function = 'ARRAY_APPEND'
|
||||||
|
|
||||||
|
# end ArrayApppend
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayToString(Function):
|
||||||
|
""" sql: array_to_string
|
||||||
|
"""
|
||||||
|
__slots__ = ()
|
||||||
|
_function = 'ARRAY_TO_STRING'
|
||||||
|
|
||||||
|
# end ArrayToString
|
||||||
|
|
||||||
|
|
||||||
|
class Array(Function):
|
||||||
|
""" sql: array-type
|
||||||
|
"""
|
||||||
|
__slots__ = ()
|
||||||
|
_function = 'ARRAY'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self._function + '[' + ', '.join(
|
||||||
|
map(self._format, self.args)) + ']'
|
||||||
|
|
||||||
|
# end Array
|
||||||
|
|
||||||
|
|
||||||
sel_categorytype = [
|
sel_categorytype = [
|
||||||
|
@ -17,7 +51,7 @@ sel_categorytype = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
|
class Category(tree(separator='/'), ModelSQL, ModelView):
|
||||||
'Category'
|
'Category'
|
||||||
__name__ = 'cashbook.category'
|
__name__ = 'cashbook.category'
|
||||||
|
|
||||||
|
@ -36,7 +70,6 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
|
||||||
|
|
||||||
company = fields.Many2One(string='Company', model_name='company.company',
|
company = fields.Many2One(string='Company', model_name='company.company',
|
||||||
required=True, ondelete="RESTRICT")
|
required=True, ondelete="RESTRICT")
|
||||||
sequence = fields.Integer(string='Sequence', select=True)
|
|
||||||
parent = fields.Many2One(string="Parent",
|
parent = fields.Many2One(string="Parent",
|
||||||
model_name='cashbook.category', ondelete='RESTRICT',
|
model_name='cashbook.category', ondelete='RESTRICT',
|
||||||
left='left', right='right')
|
left='left', right='right')
|
||||||
|
@ -45,15 +78,35 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
|
||||||
left = fields.Integer(string='Left', required=True, select=True)
|
left = fields.Integer(string='Left', required=True, select=True)
|
||||||
right = fields.Integer(string='Right', required=True, select=True)
|
right = fields.Integer(string='Right', required=True, select=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __register__(cls, module_name):
|
||||||
|
super(Category, cls).__register__(module_name)
|
||||||
|
cls.migrate_sequence(module_name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __setup__(cls):
|
def __setup__(cls):
|
||||||
super(Category, cls).__setup__()
|
super(Category, cls).__setup__()
|
||||||
cls._order.insert(0, ('name', 'ASC'))
|
cls._order.insert(0, ('rec_name', 'ASC'))
|
||||||
t = cls.__table__()
|
t = cls.__table__()
|
||||||
cls._sql_constraints.extend([
|
cls._sql_constraints.extend([
|
||||||
('name_uniq', Unique(t, t.name, t.company, t.parent), 'cashbook.msg_category_name_unique'),
|
('name_uniq',
|
||||||
|
Unique(t, t.name, t.company, t.parent),
|
||||||
|
'cashbook.msg_category_name_unique'),
|
||||||
|
('name2_uniq',
|
||||||
|
Exclude(t,
|
||||||
|
(t.name, Equal),
|
||||||
|
(t.cattype, Equal),
|
||||||
|
where=(t.parent == None)),
|
||||||
|
'cashbook.msg_category_name_unique'),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def migrate_sequence(cls, module_name):
|
||||||
|
""" remove colum 'sequence'
|
||||||
|
"""
|
||||||
|
table = cls.__table_handler__(module_name)
|
||||||
|
table.drop_column('sequence')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default_cattype(cls):
|
def default_cattype(cls):
|
||||||
return 'out'
|
return 'out'
|
||||||
|
@ -70,6 +123,34 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
|
||||||
def default_right():
|
def default_right():
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def order_rec_name(tables):
|
||||||
|
""" order by pos
|
||||||
|
a recursive sorting
|
||||||
|
"""
|
||||||
|
Category2 = Pool().get('cashbook.category')
|
||||||
|
tab_cat = Category2.__table__()
|
||||||
|
tab_cat2 = Category2.__table__()
|
||||||
|
table, _ = tables[None]
|
||||||
|
|
||||||
|
categories = With('id', 'name', 'name_path', recursive=True)
|
||||||
|
categories.query = tab_cat.select(
|
||||||
|
tab_cat.id, tab_cat.name, Array(tab_cat.name),
|
||||||
|
where = tab_cat.parent==None,
|
||||||
|
)
|
||||||
|
categories.query |= tab_cat2.join(categories,
|
||||||
|
condition=categories.id==tab_cat2.parent,
|
||||||
|
).select(
|
||||||
|
tab_cat2.id, tab_cat2.name, ArrayApppend(categories.name_path, tab_cat2.name),
|
||||||
|
)
|
||||||
|
categories.query.all_ = True
|
||||||
|
|
||||||
|
query = categories.select(
|
||||||
|
ArrayToString(categories.name_path, '/').as_('rec_name'),
|
||||||
|
where = table.id==categories.id,
|
||||||
|
with_ = [categories])
|
||||||
|
return [query]
|
||||||
|
|
||||||
@fields.depends('parent', '_parent_parent.cattype')
|
@fields.depends('parent', '_parent_parent.cattype')
|
||||||
def on_change_with_parent_cattype(self, name=None):
|
def on_change_with_parent_cattype(self, name=None):
|
||||||
""" get type of parent category or None
|
""" get type of parent category or None
|
||||||
|
|
29
category.xml
29
category.xml
|
@ -42,6 +42,20 @@ full copyright notices and license terms. -->
|
||||||
<field name="act_window" ref="act_category_list"/>
|
<field name="act_window" ref="act_category_list"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- domain view - list -->
|
||||||
|
<record model="ir.action.act_window.domain" id="act_category_list_domain_in">
|
||||||
|
<field name="name">Revenue</field>
|
||||||
|
<field name="sequence" eval="10"/>
|
||||||
|
<field name="domain" eval="[('cattype', '=', 'in')]" pyson="1"/>
|
||||||
|
<field name="act_window" ref="act_category_list"/>
|
||||||
|
</record>
|
||||||
|
<record model="ir.action.act_window.domain" id="act_category_list_domain_out">
|
||||||
|
<field name="name">Expense</field>
|
||||||
|
<field name="sequence" eval="20"/>
|
||||||
|
<field name="domain" eval="[('cattype', '=', 'out')]" pyson="1"/>
|
||||||
|
<field name="act_window" ref="act_category_list"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
<!-- action view - tree -->
|
<!-- action view - tree -->
|
||||||
<record model="ir.action.act_window" id="act_category_tree">
|
<record model="ir.action.act_window" id="act_category_tree">
|
||||||
<field name="name">Category</field>
|
<field name="name">Category</field>
|
||||||
|
@ -59,6 +73,21 @@ full copyright notices and license terms. -->
|
||||||
<field name="act_window" ref="act_category_tree"/>
|
<field name="act_window" ref="act_category_tree"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- domain view - tree -->
|
||||||
|
<record model="ir.action.act_window.domain" id="act_category_tree_domain_in">
|
||||||
|
<field name="name">Revenue</field>
|
||||||
|
<field name="sequence" eval="10"/>
|
||||||
|
<field name="domain" eval="[('cattype', '=', 'in')]" pyson="1"/>
|
||||||
|
<field name="act_window" ref="act_category_tree"/>
|
||||||
|
</record>
|
||||||
|
<record model="ir.action.act_window.domain" id="act_category_tree_domain_out">
|
||||||
|
<field name="name">Expense</field>
|
||||||
|
<field name="sequence" eval="20"/>
|
||||||
|
<field name="domain" eval="[('cattype', '=', 'out')]" pyson="1"/>
|
||||||
|
<field name="act_window" ref="act_category_tree"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
<!-- permission -->
|
<!-- permission -->
|
||||||
<!-- anon: deny all -->
|
<!-- anon: deny all -->
|
||||||
<record model="ir.model.access" id="access_category-anon">
|
<record model="ir.model.access" id="access_category-anon">
|
||||||
|
|
20
locale/de.po
20
locale/de.po
|
@ -318,6 +318,22 @@ msgctxt "model:ir.action.act_window.domain,name:act_line_domain_all"
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Alle"
|
msgstr "Alle"
|
||||||
|
|
||||||
|
msgctxt "model:ir.action.act_window.domain,name:act_category_tree_domain_in"
|
||||||
|
msgid "Revenue"
|
||||||
|
msgstr "Einnahmen"
|
||||||
|
|
||||||
|
msgctxt "model:ir.action.act_window.domain,name:act_category_tree_domain_out"
|
||||||
|
msgid "Expense"
|
||||||
|
msgstr "Ausgaben"
|
||||||
|
|
||||||
|
msgctxt "model:ir.action.act_window.domain,name:act_category_list_domain_in"
|
||||||
|
msgid "Revenue"
|
||||||
|
msgstr "Einnahmen"
|
||||||
|
|
||||||
|
msgctxt "model:ir.action.act_window.domain,name:act_category_list_domain_out"
|
||||||
|
msgid "Expense"
|
||||||
|
msgstr "Ausgaben"
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# ir.model.button #
|
# ir.model.button #
|
||||||
|
@ -446,6 +462,10 @@ msgctxt "field:cashbook.book,currency:"
|
||||||
msgid "Currency"
|
msgid "Currency"
|
||||||
msgstr "Währung"
|
msgstr "Währung"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.book,currency_digits:"
|
||||||
|
msgid "Currency Digits"
|
||||||
|
msgstr "Nachkommastellen Währung"
|
||||||
|
|
||||||
msgctxt "field:cashbook.book,start_balance:"
|
msgctxt "field:cashbook.book,start_balance:"
|
||||||
msgid "Initial Amount"
|
msgid "Initial Amount"
|
||||||
msgstr "Anfangsbetrag"
|
msgstr "Anfangsbetrag"
|
||||||
|
|
16
locale/en.po
16
locale/en.po
|
@ -294,6 +294,22 @@ msgctxt "model:ir.action.act_window.domain,name:act_line_domain_all"
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "All"
|
msgstr "All"
|
||||||
|
|
||||||
|
msgctxt "model:ir.action.act_window.domain,name:act_category_tree_domain_in"
|
||||||
|
msgid "Revenue"
|
||||||
|
msgstr "Revenue"
|
||||||
|
|
||||||
|
msgctxt "model:ir.action.act_window.domain,name:act_category_tree_domain_out"
|
||||||
|
msgid "Expense"
|
||||||
|
msgstr "Expense"
|
||||||
|
|
||||||
|
msgctxt "model:ir.action.act_window.domain,name:act_category_list_domain_in"
|
||||||
|
msgid "Revenue"
|
||||||
|
msgstr "Revenue"
|
||||||
|
|
||||||
|
msgctxt "model:ir.action.act_window.domain,name:act_category_list_domain_out"
|
||||||
|
msgid "Expense"
|
||||||
|
msgstr "Expense"
|
||||||
|
|
||||||
msgctxt "model:ir.model.button,string:line_wfedit_button"
|
msgctxt "model:ir.model.button,string:line_wfedit_button"
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Edit"
|
msgstr "Edit"
|
||||||
|
|
|
@ -28,6 +28,72 @@ class CategoryTestCase(ModuleTestCase):
|
||||||
}])
|
}])
|
||||||
return category
|
return category
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_category_check_rec_name(self):
|
||||||
|
""" create category, test rec_name, search, order
|
||||||
|
"""
|
||||||
|
pool = Pool()
|
||||||
|
Category = pool.get('cashbook.category')
|
||||||
|
company = self.prep_company()
|
||||||
|
|
||||||
|
Category.create([{
|
||||||
|
'company': company.id,
|
||||||
|
'name': 'Level 1',
|
||||||
|
'cattype': 'in',
|
||||||
|
'childs': [('create', [{
|
||||||
|
'company': company.id,
|
||||||
|
'name': 'Level 2a',
|
||||||
|
'cattype': 'in',
|
||||||
|
}, {
|
||||||
|
'company': company.id,
|
||||||
|
'name': 'Level 2b',
|
||||||
|
'cattype': 'in',
|
||||||
|
}])],
|
||||||
|
}, {
|
||||||
|
'company': company.id,
|
||||||
|
'name': 'Level 1b',
|
||||||
|
'cattype': 'in',
|
||||||
|
'childs': [('create', [{
|
||||||
|
'company': company.id,
|
||||||
|
'name': 'Level 1b.2a',
|
||||||
|
'cattype': 'in',
|
||||||
|
}, {
|
||||||
|
'company': company.id,
|
||||||
|
'name': 'Level 1b.2b',
|
||||||
|
'cattype': 'in',
|
||||||
|
}])],
|
||||||
|
}])
|
||||||
|
|
||||||
|
self.assertEqual(Category.search_count([
|
||||||
|
('rec_name', 'ilike', '%1b.2b%'),
|
||||||
|
]), 1)
|
||||||
|
self.assertEqual(Category.search_count([
|
||||||
|
('rec_name', 'ilike', '%1b.2%'),
|
||||||
|
]), 2)
|
||||||
|
self.assertEqual(Category.search_count([
|
||||||
|
('rec_name', '=', 'Level 1b/Level 1b.2b'),
|
||||||
|
]), 1)
|
||||||
|
|
||||||
|
# ordering #1
|
||||||
|
categories = Category.search([], order=[('rec_name', 'ASC')])
|
||||||
|
self.assertEqual(len(categories), 6)
|
||||||
|
self.assertEqual(categories[0].rec_name, 'Level 1')
|
||||||
|
self.assertEqual(categories[1].rec_name, 'Level 1b')
|
||||||
|
self.assertEqual(categories[2].rec_name, 'Level 1b/Level 1b.2a')
|
||||||
|
self.assertEqual(categories[3].rec_name, 'Level 1b/Level 1b.2b')
|
||||||
|
self.assertEqual(categories[4].rec_name, 'Level 1/Level 2a')
|
||||||
|
self.assertEqual(categories[5].rec_name, 'Level 1/Level 2b')
|
||||||
|
|
||||||
|
# ordering #2
|
||||||
|
categories = Category.search([], order=[('rec_name', 'DESC')])
|
||||||
|
self.assertEqual(len(categories), 6)
|
||||||
|
self.assertEqual(categories[0].rec_name, 'Level 1/Level 2b')
|
||||||
|
self.assertEqual(categories[1].rec_name, 'Level 1/Level 2a')
|
||||||
|
self.assertEqual(categories[2].rec_name, 'Level 1b/Level 1b.2b')
|
||||||
|
self.assertEqual(categories[3].rec_name, 'Level 1b/Level 1b.2a')
|
||||||
|
self.assertEqual(categories[4].rec_name, 'Level 1b')
|
||||||
|
self.assertEqual(categories[5].rec_name, 'Level 1')
|
||||||
|
|
||||||
@with_transaction()
|
@with_transaction()
|
||||||
def test_category_create_check_category_type(self):
|
def test_category_create_check_category_type(self):
|
||||||
""" create category, update type of category
|
""" create category, update type of category
|
||||||
|
@ -90,6 +156,7 @@ class CategoryTestCase(ModuleTestCase):
|
||||||
cat1, = Category.create([{
|
cat1, = Category.create([{
|
||||||
'name': 'Test 1',
|
'name': 'Test 1',
|
||||||
'description': 'Info',
|
'description': 'Info',
|
||||||
|
'cattype': 'in',
|
||||||
}])
|
}])
|
||||||
self.assertEqual(cat1.name, 'Test 1')
|
self.assertEqual(cat1.name, 'Test 1')
|
||||||
self.assertEqual(cat1.rec_name, 'Test 1')
|
self.assertEqual(cat1.rec_name, 'Test 1')
|
||||||
|
@ -97,10 +164,11 @@ class CategoryTestCase(ModuleTestCase):
|
||||||
self.assertEqual(cat1.company.rec_name, 'm-ds')
|
self.assertEqual(cat1.company.rec_name, 'm-ds')
|
||||||
self.assertEqual(cat1.parent, None)
|
self.assertEqual(cat1.parent, None)
|
||||||
|
|
||||||
# duplicate, allowed
|
# duplicate of different type, allowed
|
||||||
cat2, = Category.create([{
|
cat2, = Category.create([{
|
||||||
'name': 'Test 1',
|
'name': 'Test 1',
|
||||||
'description': 'Info',
|
'description': 'Info',
|
||||||
|
'cattype': 'out',
|
||||||
}])
|
}])
|
||||||
self.assertEqual(cat2.name, 'Test 1')
|
self.assertEqual(cat2.name, 'Test 1')
|
||||||
self.assertEqual(cat2.rec_name, 'Test 1')
|
self.assertEqual(cat2.rec_name, 'Test 1')
|
||||||
|
@ -108,6 +176,16 @@ class CategoryTestCase(ModuleTestCase):
|
||||||
self.assertEqual(cat2.company.rec_name, 'm-ds')
|
self.assertEqual(cat2.company.rec_name, 'm-ds')
|
||||||
self.assertEqual(cat2.parent, None)
|
self.assertEqual(cat2.parent, None)
|
||||||
|
|
||||||
|
# deny duplicate of same type
|
||||||
|
self.assertRaisesRegex(UserError,
|
||||||
|
'The category name already exists at this level.',
|
||||||
|
Category.create,
|
||||||
|
[{
|
||||||
|
'name': 'Test 1',
|
||||||
|
'description': 'Info',
|
||||||
|
'cattype': 'in',
|
||||||
|
}])
|
||||||
|
|
||||||
@with_transaction()
|
@with_transaction()
|
||||||
def test_category_create_nodupl_diff_level(self):
|
def test_category_create_nodupl_diff_level(self):
|
||||||
""" create category
|
""" create category
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[tryton]
|
[tryton]
|
||||||
version=6.0.0
|
version=6.0.3
|
||||||
depends:
|
depends:
|
||||||
res
|
res
|
||||||
currency
|
currency
|
||||||
|
|
|
@ -18,8 +18,7 @@ full copyright notices and license terms. -->
|
||||||
<field name="company"/>
|
<field name="company"/>
|
||||||
<label name="parent"/>
|
<label name="parent"/>
|
||||||
<field name="parent"/>
|
<field name="parent"/>
|
||||||
<label name="sequence"/>
|
<newline/>
|
||||||
<field name="sequence"/>
|
|
||||||
<field name="childs" colspan="6"/>
|
<field name="childs" colspan="6"/>
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
<!-- This file is part of the cashbook-module from m-ds for Tryton.
|
<!-- This file is part of the cashbook-module from m-ds for Tryton.
|
||||||
The COPYRIGHT file at the top level of this repository contains the
|
The COPYRIGHT file at the top level of this repository contains the
|
||||||
full copyright notices and license terms. -->
|
full copyright notices and license terms. -->
|
||||||
<tree sequence="sequence">
|
<tree>
|
||||||
<field name="rec_name"/>
|
<field name="rec_name"/>
|
||||||
<field name="cattype"/>
|
|
||||||
<field name="sequence" tree_invisible="1"/>
|
|
||||||
</tree>
|
</tree>
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
<!-- This file is part of the cashbook-module from m-ds for Tryton.
|
<!-- This file is part of the cashbook-module from m-ds for Tryton.
|
||||||
The COPYRIGHT file at the top level of this repository contains the
|
The COPYRIGHT file at the top level of this repository contains the
|
||||||
full copyright notices and license terms. -->
|
full copyright notices and license terms. -->
|
||||||
<tree sequence="sequence">
|
<tree >
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="cattype"/>
|
|
||||||
<field name="sequence" tree_invisible="1"/>
|
|
||||||
<field name="parent" tree_invisible="1"/>
|
<field name="parent" tree_invisible="1"/>
|
||||||
<field name="childs" tree_invisible="1"/>
|
<field name="childs" tree_invisible="1"/>
|
||||||
</tree>
|
</tree>
|
||||||
|
|
Loading…
Reference in a new issue