diff --git a/README.rst b/README.rst
index 97408f7..aa52d7c 100644
--- a/README.rst
+++ b/README.rst
@@ -14,6 +14,23 @@ Requires
Changes
=======
+*6.0.4 - 05.09.2022*
+
+- fix: write number at state-change 'check' -> 'done'
+- updt: speedup transaction view
+
+*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*
- init
diff --git a/book.py b/book.py
index dd92f35..2adfb4f 100644
--- a/book.py
+++ b/book.py
@@ -76,14 +76,16 @@ class Book(Workflow, ModelSQL, ModelView):
),
}, depends=DEPENDS+['lines'])
start_balance = fields.Numeric(string='Initial Amount', required=True,
+ digits=(16, Eval('currency_digits', 2)),
states={
'readonly': Or(
STATES['readonly'],
Bool(Eval('lines')),
),
- }, depends=DEPENDS+['lines'])
- balance = fields.Function(fields.Numeric(string='Balance', readonly=True),
- 'on_change_with_balance')
+ }, depends=DEPENDS+['lines', 'currency_digits'])
+ balance = fields.Function(fields.Numeric(string='Balance', readonly=True,
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'on_change_with_balance')
currency = fields.Many2One(string='Currency', required=True,
model_name='currency.currency',
states={
@@ -92,6 +94,8 @@ class Book(Workflow, ModelSQL, ModelView):
Bool(Eval('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,
readonly=True, selection=sel_state_book)
state_string = state.translated('state')
@@ -196,6 +200,15 @@ class Book(Workflow, ModelSQL, ModelView):
'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')
def on_change_with_balance(self, name=None):
""" compute balance
diff --git a/category.py b/category.py
index 0d23eb8..477016c 100644
--- a/category.py
+++ b/category.py
@@ -3,12 +3,46 @@
# The COPYRIGHT file at the top level of this repository contains the
# 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.pool import Pool
from trytond.pyson import Eval, If, Bool
from trytond.exceptions import UserError
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 = [
@@ -17,7 +51,7 @@ sel_categorytype = [
]
-class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
+class Category(tree(separator='/'), ModelSQL, ModelView):
'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',
required=True, ondelete="RESTRICT")
- sequence = fields.Integer(string='Sequence', select=True)
parent = fields.Many2One(string="Parent",
model_name='cashbook.category', ondelete='RESTRICT',
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)
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
def __setup__(cls):
super(Category, cls).__setup__()
- cls._order.insert(0, ('name', 'ASC'))
+ cls._order.insert(0, ('rec_name', 'ASC'))
t = cls.__table__()
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
def default_cattype(cls):
return 'out'
@@ -70,6 +123,34 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
def default_right():
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')
def on_change_with_parent_cattype(self, name=None):
""" get type of parent category or None
diff --git a/category.xml b/category.xml
index a5dcc66..516e4c7 100644
--- a/category.xml
+++ b/category.xml
@@ -42,6 +42,20 @@ full copyright notices and license terms. -->
+
+
+ Revenue
+
+
+
+
+
+ Expense
+
+
+
+
+
Category
@@ -59,6 +73,21 @@ full copyright notices and license terms. -->
+
+
+ Revenue
+
+
+
+
+
+ Expense
+
+
+
+
+
+
diff --git a/line.py b/line.py
index a8ccda4..e12e19f 100644
--- a/line.py
+++ b/line.py
@@ -57,8 +57,10 @@ class Line(Workflow, ModelSQL, ModelView):
month = fields.Function(fields.Integer(string='Month', readonly=True),
'on_change_with_month', searcher='search_month')
number = fields.Char(string='Number', readonly=True)
- description = fields.Text(string='Description',
+ description = fields.Text(string='Description', select=True,
states=STATES, depends=DEPENDS)
+ descr_short = fields.Function(fields.Char(string='Description', readonly=True),
+ 'on_change_with_descr_short', searcher='search_descr_short')
category = fields.Many2One(string='Category',
model_name='cashbook.category', ondelete='RESTRICT',
states={
@@ -414,6 +416,13 @@ class Line(Workflow, ModelSQL, ModelView):
return [tab2]
+ @staticmethod
+ def order_descr_short(tables):
+ """ order by 'description'
+ """
+ table, _ = tables[None]
+ return [table.description]
+
@classmethod
def search_payee(cls, names, clause):
""" search in payee for party or cashbook
@@ -454,6 +463,12 @@ class Line(Workflow, ModelSQL, ModelView):
"""
return [('cashbook.state',) + tuple(clause[1:])]
+ @classmethod
+ def search_descr_short(cls, names, clause):
+ """ search in description
+ """
+ return [('description',) + tuple(clause[1:])]
+
@fields.depends('amount', 'splitlines')
def on_change_splitlines(self):
""" update amount if splitlines change
@@ -481,6 +496,13 @@ class Line(Workflow, ModelSQL, ModelView):
else :
self.splitlines = []
+ @fields.depends('description')
+ def on_change_with_descr_short(self, name=None):
+ """ to speed up list-view
+ """
+ if self.description:
+ return self.description[:25]
+
@fields.depends('party', 'booktransf', 'bookingtype')
def on_change_with_payee(self, name=None):
""" get party or cashbook
@@ -549,7 +571,8 @@ class Line(Workflow, ModelSQL, ModelView):
@fields.depends('id', 'date', 'cashbook', \
'_parent_cashbook.start_balance', '_parent_cashbook.id',\
- 'reconciliation', '_parent_reconciliation.start_amount')
+ 'reconciliation', '_parent_reconciliation.start_amount',
+ '_parent_reconciliation.state')
def on_change_with_balance(self, name=None):
""" compute balance until current line, with current sort order,
try to use a reconciliation as start to speed up calculation
@@ -558,6 +581,30 @@ class Line(Workflow, ModelSQL, ModelView):
Reconciliation = pool.get('cashbook.recon')
Line = pool.get('cashbook.line')
+ def get_from_last_recon(line2):
+ """ search last reconciliation in state 'done',
+ generate query
+ """
+ query2 = []
+ end_amount = None
+
+ recons = Reconciliation.search([
+ ('cashbook.id', '=', self.cashbook.id),
+ ('date_to', '<=', line2.date),
+ ('state', '=', 'done'),
+ ], order=[('date_from', 'DESC')], limit=1)
+ if len(recons) > 0:
+ query2.append([
+ ('date', '>=', recons[0].date_to),
+ ('date', '<=', line2.date),
+ ['OR',
+ ('reconciliation', '=', None),
+ ('reconciliation.id', '!=', recons[0]),
+ ],
+ ])
+ end_amount = recons[0].end_amount
+ return (query2, end_amount)
+
if self.cashbook:
query = [
('cashbook.id', '=', self.cashbook.id),
@@ -567,22 +614,22 @@ class Line(Workflow, ModelSQL, ModelView):
# get existing reconciliation, starting before current line
# this will speed up calculation of by-line-balance
if self.date is not None:
- recons = Reconciliation.search([
- ('cashbook.id', '=', self.cashbook.id),
- ('date_from', '<=', self.date),
- ('state', '=', 'done'),
- ], order=[('date_from', 'DESC')], limit=1)
- if len(recons) > 0:
- query.extend([
- ['OR',
- ('date', '>', recons[0].date_from),
- [
- ('date', '=', recons[0].date_from),
- ('reconciliation.id', '=',recons[0].id),
- ],
- ]
- ])
- balance = recons[0].start_amount
+ if self.reconciliation:
+ if self.reconciliation.state == 'done':
+ query.append(
+ ('reconciliation.id', '=', self.reconciliation.id),
+ )
+ balance = self.reconciliation.start_amount
+ else :
+ (query2, balance2) = get_from_last_recon(self)
+ query.extend(query2)
+ if balance2 is not None:
+ balance = balance2
+ else :
+ (query2, balance2) = get_from_last_recon(self)
+ query.extend(query2)
+ if balance2 is not None:
+ balance = balance2
lines = Line.search(query)
for line in lines:
@@ -722,7 +769,7 @@ class Line(Workflow, ModelSQL, ModelView):
# deny write if line is not 'Edit'
if line.state != 'edit':
# allow state-update, if its the only action
- if not ((len(set({'state', 'reconciliation'}).intersection(values.keys())) > 0) \
+ if not ((len(set({'state', 'reconciliation', 'number'}).intersection(values.keys())) > 0) \
and (len(values.keys()) == 1)):
raise UserError(gettext(
'cashbook.msg_line_deny_write',
diff --git a/locale/de.po b/locale/de.po
index 073d916..7faf37b 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -318,6 +318,22 @@ msgctxt "model:ir.action.act_window.domain,name:act_line_domain_all"
msgid "All"
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 #
@@ -390,6 +406,10 @@ msgctxt "view:cashbook.book:"
msgid "Owner and Authorizeds"
msgstr "Eigentümer und Autorisierte"
+msgctxt "view:cashbook.book:"
+msgid "Balance"
+msgstr "Saldo"
+
msgctxt "view:cashbook.book:"
msgid "Reconciliations"
msgstr "Abstimmungen"
@@ -446,6 +466,10 @@ msgctxt "field:cashbook.book,currency:"
msgid "Currency"
msgstr "Währung"
+msgctxt "field:cashbook.book,currency_digits:"
+msgid "Currency Digits"
+msgstr "Nachkommastellen Währung"
+
msgctxt "field:cashbook.book,start_balance:"
msgid "Initial Amount"
msgstr "Anfangsbetrag"
@@ -618,6 +642,10 @@ msgctxt "field:cashbook.line,description:"
msgid "Description"
msgstr "Beschreibung"
+msgctxt "field:cashbook.line,descr_short:"
+msgid "Description"
+msgstr "Beschreibung"
+
msgctxt "field:cashbook.line,state:"
msgid "State"
msgstr "Status"
diff --git a/locale/en.po b/locale/en.po
index c6f7965..fa127f3 100644
--- a/locale/en.po
+++ b/locale/en.po
@@ -294,6 +294,22 @@ msgctxt "model:ir.action.act_window.domain,name:act_line_domain_all"
msgid "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"
msgid "Edit"
msgstr "Edit"
@@ -354,6 +370,10 @@ msgctxt "view:cashbook.book:"
msgid "Owner and Authorizeds"
msgstr "Owner and Authorizeds"
+msgctxt "view:cashbook.book:"
+msgid "Balance"
+msgstr "Balance"
+
msgctxt "view:cashbook.book:"
msgid "Reconciliations"
msgstr "Reconciliations"
@@ -410,6 +430,10 @@ msgctxt "field:cashbook.book,currency:"
msgid "Currency"
msgstr "Currency"
+msgctxt "field:cashbook.book,currency_digits:"
+msgid "Currency Digits"
+msgstr "Currency Digits"
+
msgctxt "field:cashbook.book,start_balance:"
msgid "Initial Amount"
msgstr "Initial Amount"
@@ -574,6 +598,10 @@ msgctxt "field:cashbook.line,description:"
msgid "Description"
msgstr "Description"
+msgctxt "field:cashbook.line,descr_short:"
+msgid "Description"
+msgstr "Description"
+
msgctxt "field:cashbook.line,state:"
msgid "State"
msgstr "State"
diff --git a/tests/test_category.py b/tests/test_category.py
index bfea57e..898e699 100644
--- a/tests/test_category.py
+++ b/tests/test_category.py
@@ -28,6 +28,72 @@ class CategoryTestCase(ModuleTestCase):
}])
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()
def test_category_create_check_category_type(self):
""" create category, update type of category
@@ -90,6 +156,7 @@ class CategoryTestCase(ModuleTestCase):
cat1, = Category.create([{
'name': 'Test 1',
'description': 'Info',
+ 'cattype': 'in',
}])
self.assertEqual(cat1.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.parent, None)
- # duplicate, allowed
+ # duplicate of different type, allowed
cat2, = Category.create([{
'name': 'Test 1',
'description': 'Info',
+ 'cattype': 'out',
}])
self.assertEqual(cat2.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.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()
def test_category_create_nodupl_diff_level(self):
""" create category
diff --git a/tests/test_line.py b/tests/test_line.py
index e08d0b1..32e175b 100644
--- a/tests/test_line.py
+++ b/tests/test_line.py
@@ -366,6 +366,93 @@ class LineTestCase(ModuleTestCase):
self.assertEqual(book.lines[3].reconciliation, None)
self.assertEqual(book.lines[3].state, 'edit')
+ @with_transaction()
+ def test_line_set_number_with_done(self):
+ """ create cashbook + line, write number to line
+ at state-change check->done
+ """
+ pool = Pool()
+ Book = pool.get('cashbook.book')
+ Lines = pool.get('cashbook.line')
+ Reconciliation = pool.get('cashbook.recon')
+
+ types = self.prep_type()
+ category = self.prep_category(cattype='in')
+ company = self.prep_company()
+ party = self.prep_party()
+ with Transaction().set_context({
+ 'company': company.id,
+ }):
+ book, = Book.create([{
+ 'name': 'Book 1',
+ 'btype': types.id,
+ 'company': company.id,
+ 'currency': company.currency.id,
+ 'number_sequ': self.prep_sequence().id,
+ 'start_date': date(2022, 5, 1),
+ 'number_atcheck': False,
+ 'lines': [('create', [{
+ 'date': date(2022, 5, 1),
+ 'description': 'Text 1',
+ 'category': category.id,
+ 'bookingtype': 'in',
+ 'amount': Decimal('1.0'),
+ 'party': party.id,
+ }, {
+ 'date': date(2022, 5, 2),
+ 'description': 'Text 2',
+ 'category': category.id,
+ 'bookingtype': 'in',
+ 'amount': Decimal('1.0'),
+ 'party': party.id,
+ }])],
+ }])
+ self.assertEqual(book.name, 'Book 1')
+ self.assertEqual(book.btype.rec_name, 'CAS - Cash')
+ self.assertEqual(book.state, 'open')
+ self.assertEqual(book.number_atcheck, False)
+ self.assertEqual(len(book.lines), 2)
+ self.assertEqual(book.lines[0].date, date(2022, 5, 1))
+ self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
+ self.assertEqual(book.lines[0].state_cashbook, 'open')
+ self.assertEqual(book.lines[1].date, date(2022, 5, 2))
+ self.assertEqual(book.lines[1].rec_name, '05/02/2022|Rev|1.00 usd|Text 2 [Cat1]')
+
+ # add reconciliation
+ Book.write(*[
+ [book],
+ {
+ 'reconciliations': [('create', [{
+ 'date': date(2022, 5, 1),
+ 'date_from': date(2022, 5, 1),
+ 'date_to': date(2022, 5, 30),
+ }])],
+ }])
+ self.assertEqual(len(book.reconciliations), 1)
+ self.assertEqual(len(book.reconciliations[0].lines), 0)
+ self.assertEqual(book.reconciliations[0].date_from, date(2022, 5, 1))
+ self.assertEqual(book.reconciliations[0].date_to, date(2022, 5, 30))
+ self.assertEqual(book.reconciliations[0].state, 'edit')
+
+ Lines.wfcheck(book.lines)
+ self.assertEqual(book.lines[0].state, 'check')
+ self.assertEqual(book.lines[0].number, None)
+ self.assertEqual(book.lines[1].state, 'check')
+ self.assertEqual(book.lines[1].number, None)
+
+ Reconciliation.wfcheck(book.reconciliations)
+ self.assertEqual(len(book.reconciliations[0].lines), 2)
+ self.assertEqual(book.reconciliations[0].lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
+ self.assertEqual(book.reconciliations[0].lines[1].rec_name, '05/02/2022|Rev|1.00 usd|Text 2 [Cat1]')
+ self.assertEqual(book.reconciliations[0].lines[0].number, None)
+ self.assertEqual(book.reconciliations[0].lines[1].number, None)
+
+ Reconciliation.wfdone(book.reconciliations)
+ self.assertEqual(book.reconciliations[0].lines[0].number, '1')
+ self.assertEqual(book.reconciliations[0].lines[0].state, 'done')
+ self.assertEqual(book.reconciliations[0].lines[1].number, '2')
+ self.assertEqual(book.reconciliations[0].lines[1].state, 'done')
+
@with_transaction()
def test_line_create_check_names_search(self):
""" create cashbook + line
diff --git a/tryton.cfg b/tryton.cfg
index dab4bf6..c44af8b 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -1,5 +1,5 @@
[tryton]
-version=6.0.0
+version=6.0.4
depends:
res
currency
diff --git a/view/book_list.xml b/view/book_list.xml
index 91dc2fd..73d2795 100644
--- a/view/book_list.xml
+++ b/view/book_list.xml
@@ -6,7 +6,7 @@ full copyright notices and license terms. -->
-
+
diff --git a/view/category_form.xml b/view/category_form.xml
index 093c4d6..9ea7a6e 100644
--- a/view/category_form.xml
+++ b/view/category_form.xml
@@ -18,8 +18,7 @@ full copyright notices and license terms. -->
-
-
+
diff --git a/view/category_list.xml b/view/category_list.xml
index f3ca367..9e613dd 100644
--- a/view/category_list.xml
+++ b/view/category_list.xml
@@ -2,8 +2,6 @@
-
+
-
-
diff --git a/view/category_tree.xml b/view/category_tree.xml
index ccc59bd..03abb9f 100644
--- a/view/category_tree.xml
+++ b/view/category_tree.xml
@@ -2,10 +2,8 @@
-
+
-
-
diff --git a/view/line_list.xml b/view/line_list.xml
index 355c450..aec30bb 100644
--- a/view/line_list.xml
+++ b/view/line_list.xml
@@ -7,8 +7,7 @@ full copyright notices and license terms. -->
-
-
+