kategorie: sequence-sortierung, rec_name mit/ohne konto-nr,

config: Felder catnamelong+cataccno neu + tests,
line: feld category_view neu für spaltenansicht in kassenbuch + tests,
This commit is contained in:
Frederik Jaeckel 2022-08-10 11:57:35 +02:00
parent a23407f515
commit 1a85b8e80e
15 changed files with 414 additions and 104 deletions

View file

@ -3,11 +3,12 @@
# 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
from trytond.model import ModelView, ModelSQL, fields, Unique, tree, sequence_ordered
from trytond.transaction import Transaction
from trytond.pool import Pool
class Category(tree(separator='/'), ModelSQL, ModelView):
class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
'Category'
__name__ = 'cashbook.category'
@ -20,6 +21,7 @@ class Category(tree(separator='/'), 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')
@ -50,15 +52,26 @@ class Category(tree(separator='/'), ModelSQL, ModelView):
def default_right():
return 0
def get_long_recname(self, recname):
""" build rec_name with account-no
"""
Configuration = Pool().get('cashbook.configuration')
l1 = [recname]
if self.account:
if self.account.code:
cfg1 = Configuration.get_singleton()
if getattr(cfg1, 'cataccno', True) == True:
l1.append('[%s]' % self.account.code)
return ' '.join(l1)
def get_rec_name(self, name):
""" short + name
"""
l1 = []
if self.account:
if self.account.code:
l1.append(self.account.code)
l1.append(super(Category, self).get_rec_name(name))
return ' '.join(l1)
return self.get_long_recname(
super(Category, self).get_rec_name(name)
)
@classmethod
def search_rec_name(cls, name, clause):
@ -67,6 +80,7 @@ class Category(tree(separator='/'), ModelSQL, ModelView):
return ['OR',
super(Category, cls).search_rec_name(name, clause),
('account.rec_name',) + tuple(clause[1:]),
('account.code',) + tuple(clause[1:]),
]
@fields.depends('account')

View file

@ -9,6 +9,16 @@ from trytond.pyson import Eval, If
from trytond.pool import Pool
field_checked = fields.Boolean(string='Checked',
help='Show cashbook lines in Checked-state.')
field_done = fields.Boolean(string='Done',
help='Show cashbook lines in Done-state.')
field_catnamelong = fields.Boolean(string='Category: Show long name',
help='Shows the long name of the category in the Category field of a cash book line.')
field_cataccno = fields.Boolean(string='Category: Show account number',
help='Shows the number of the linked account in the name of a category.')
class Configuration(ModelSingleton, ModelSQL, ModelView, UserMultiValueMixin):
'Configuration'
__name__ = 'cashbook.configuration'
@ -25,8 +35,10 @@ class Configuration(ModelSingleton, ModelSQL, ModelView, UserMultiValueMixin):
('date_from', '<=', Eval('date_to')),
()),
]))
checked = fields.MultiValue(fields.Boolean(string='Checked'))
done = fields.MultiValue(fields.Boolean(string='Done'))
checked = fields.MultiValue(field_checked)
done = fields.MultiValue(field_done)
catnamelong = fields.MultiValue(field_catnamelong)
cataccno = fields.MultiValue(field_cataccno)
@classmethod
def multivalue_model(cls, field):
@ -34,7 +46,8 @@ class Configuration(ModelSingleton, ModelSQL, ModelView, UserMultiValueMixin):
"""
pool = Pool()
if field in ['date_from', 'date_to', 'checked', 'done']:
if field in ['date_from', 'date_to', 'checked', 'done',
'catnamelong', 'cataccno']:
return pool.get('cashbook.configuration_user')
return super(Configuration, cls).multivalue_model(field)
@ -46,6 +59,14 @@ class Configuration(ModelSingleton, ModelSQL, ModelView, UserMultiValueMixin):
def default_done(cls, **pattern):
return cls.multivalue_model('done').default_done()
@classmethod
def default_catnamelong(cls, **pattern):
return cls.multivalue_model('catnamelong').default_catnamelong()
@classmethod
def default_cataccno(cls, **pattern):
return cls.multivalue_model('cataccno').default_cataccno()
# end Configuration
@ -65,13 +86,23 @@ class UserConfiguration(ModelSQL, UserValueMixin):
('date_from', '<=', Eval('date_to')),
()),
])
checked = fields.Boolean(string='Checked')
done = fields.Boolean(string='Done')
checked = field_checked
done = field_done
catnamelong = field_catnamelong
cataccno = field_cataccno
@classmethod
def default_checked(cls):
return True
@classmethod
def default_catnamelong(cls):
return True
@classmethod
def default_cataccno(cls):
return True
@classmethod
def default_done(cls):
return False

View file

@ -20,5 +20,58 @@ full copyright notices and license terms. -->
<field name="act_window" ref="act_configuration_form"/>
</record>
<!-- permission -->
<!-- anon: deny all -->
<record model="ir.model.access" id="access_config-anon">
<field name="model" search="[('model', '=', 'cashbook.configuration')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<!-- admin: read/write -->
<record model="ir.model.access" id="access_config-group_admin">
<field name="model" search="[('model', '=', 'cashbook.configuration')]"/>
<field name="group" ref="res.group_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.model.access" id="access_config-group_cashbook">
<field name="model" search="[('model', '=', 'cashbook.configuration')]"/>
<field name="group" ref="group_cashbook"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- anon: deny all -->
<record model="ir.model.access" id="access_config_user-anon">
<field name="model" search="[('model', '=', 'cashbook.configuration_user')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<!-- admin: read/write -->
<record model="ir.model.access" id="access_config_user-group_admin">
<field name="model" search="[('model', '=', 'cashbook.configuration_user')]"/>
<field name="group" ref="res.group_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.model.access" id="access_config_user-group_cashbook">
<field name="model" search="[('model', '=', 'cashbook.configuration_user')]"/>
<field name="group" ref="group_cashbook"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
</data>
</tryton>

205
line.py
View file

@ -30,91 +30,6 @@ STATES = {
DEPENDS=['state', 'state_cashbook']
class LineContext(ModelView):
'Line Context'
__name__ = 'cashbook.line.context'
cashbook = fields.Many2One(string='Cashbook', required=True,
model_name='cashbook.book',
states={
'readonly': Eval('num_cashbook', 0) < 2,
}, depends=['num_cashbook'])
date_from = fields.Date(string='Start Date', depends=['date_to'],
domain=[
If(Eval('date_to') & Eval('date_from'),
('date_from', '<=', Eval('date_to')),
()),
])
date_to = fields.Date(string='End Date', depends=['date_from'],
domain=[
If(Eval('date_to') & Eval('date_from'),
('date_from', '<=', Eval('date_to')),
()),
])
checked = fields.Boolean(string='Checked',
help='Show account lines in Checked-state.')
done = fields.Boolean(string='Done',
help='Show account lines in Done-state.')
num_cashbook = fields.Function(fields.Integer(string='Number of Cashbook',
readonly=True, states={'invisible': True}),
'on_change_with_num_cashbook')
@classmethod
def default_cashbook(cls):
""" get default from context
"""
context = Transaction().context
return context.get('cashbook', None)
@classmethod
def default_date_from(cls):
""" get default from context
"""
context = Transaction().context
return context.get('date_from', None)
@classmethod
def default_date_to(cls):
""" get default from context
"""
context = Transaction().context
return context.get('date_to', None)
@classmethod
def default_checked(cls):
""" get default from context
"""
context = Transaction().context
return context.get('checked', False)
@classmethod
def default_num_cashbook(cls):
""" get default from context
"""
CashBook = Pool().get('cashbook.book')
with Transaction().set_context({
'_check_access': True,
}):
return CashBook.search_count([])
@classmethod
def default_done(cls):
""" get default from context
"""
context = Transaction().context
return context.get('done', False)
def on_change_with_num_cashbook(self, name=None):
""" get number of accessible cashbooks,
depends on user-permissions
"""
LineContext = Pool().get('cashbook.line.context')
return LineContext.default_num_cashbook()
# end LineContext
class Line(Workflow, ModelSQL, ModelView):
'Cashbook Line'
__name__ = 'cashbook.line'
@ -130,6 +45,8 @@ class Line(Workflow, ModelSQL, ModelView):
category = fields.Many2One(string='Category', required=True,
model_name='cashbook.category', ondelete='RESTRICT',
states=STATES, depends=DEPENDS)
category_view = fields.Function(fields.Char(string='Category', readonly=True),
'on_change_with_category_view', searcher='search_category_view')
state = fields.Selection(string='State', required=True, readonly=True,
select=True, selection=sel_linetype)
state_string = state.translated('state')
@ -221,6 +138,39 @@ class Line(Workflow, ModelSQL, ModelView):
'desc': (self.description or '-')[:40],
}
@staticmethod
def order_category_view(tables):
""" order: name
"""
table, _ = tables[None]
Category = Pool().get('cashbook.category')
tab_cat = Category.__table__()
tab2 = tab_cat.select(tab_cat.name,
where=tab_cat.id==table.category
)
return [tab2]
@classmethod
def search_category_view(cls, name, clause):
""" search in category
"""
return [('category.rec_name',) + tuple(clause[1:])]
@fields.depends('category')
def on_change_with_category_view(self, name=None):
""" show optimizef form of category for list-view
"""
Configuration = Pool().get('cashbook.configuration')
if self.category:
cfg1 = Configuration.get_singleton()
if getattr(cfg1, 'catnamelong', True) == True:
return self.category.rec_name
else :
return self.category.get_long_recname(self.category.name)
@classmethod
def search_rec_name(cls, name, clause):
""" search in description +...
@ -306,3 +256,88 @@ class Line(Workflow, ModelSQL, ModelView):
return super(Line, cls).delete(lines)
# end Line
class LineContext(ModelView):
'Line Context'
__name__ = 'cashbook.line.context'
cashbook = fields.Many2One(string='Cashbook', required=True,
model_name='cashbook.book',
states={
'readonly': Eval('num_cashbook', 0) < 2,
}, depends=['num_cashbook'])
date_from = fields.Date(string='Start Date', depends=['date_to'],
domain=[
If(Eval('date_to') & Eval('date_from'),
('date_from', '<=', Eval('date_to')),
()),
])
date_to = fields.Date(string='End Date', depends=['date_from'],
domain=[
If(Eval('date_to') & Eval('date_from'),
('date_from', '<=', Eval('date_to')),
()),
])
checked = fields.Boolean(string='Checked',
help='Show account lines in Checked-state.')
done = fields.Boolean(string='Done',
help='Show account lines in Done-state.')
num_cashbook = fields.Function(fields.Integer(string='Number of Cashbook',
readonly=True, states={'invisible': True}),
'on_change_with_num_cashbook')
@classmethod
def default_cashbook(cls):
""" get default from context
"""
context = Transaction().context
return context.get('cashbook', None)
@classmethod
def default_date_from(cls):
""" get default from context
"""
context = Transaction().context
return context.get('date_from', None)
@classmethod
def default_date_to(cls):
""" get default from context
"""
context = Transaction().context
return context.get('date_to', None)
@classmethod
def default_checked(cls):
""" get default from context
"""
context = Transaction().context
return context.get('checked', False)
@classmethod
def default_num_cashbook(cls):
""" get default from context
"""
CashBook = Pool().get('cashbook.book')
with Transaction().set_context({
'_check_access': True,
}):
return CashBook.search_count([])
@classmethod
def default_done(cls):
""" get default from context
"""
context = Transaction().context
return context.get('done', False)
def on_change_with_num_cashbook(self, name=None):
""" get number of accessible cashbooks,
depends on user-permissions
"""
LineContext = Pool().get('cashbook.line.context')
return LineContext.default_num_cashbook()
# end LineContext

View file

@ -46,6 +46,10 @@ msgctxt "model:ir.message,text:msg_category_name_unique"
msgid "The category name already exists at this level."
msgstr "Der Kategoriename existiert auf dieser Ebene bereits."
msgctxt "model:ir.message,text:msg_category_account_unique"
msgid "The account is already in use for a category."
msgstr "Das Konto wird bereits für eine Kategorie verwendet."
#############
# res.group #
@ -286,6 +290,10 @@ msgctxt "field:cashbook.line,category:"
msgid "Category"
msgstr "Kategorie"
msgctxt "field:cashbook.line,category_view:"
msgid "Category"
msgstr "Kategorie"
msgctxt "model:ir.action.act_window.domain,name:act_line_domain_current"
msgid "Current Month"
msgstr "aktueller Monat"
@ -482,6 +490,10 @@ msgctxt "view:cashbook.configuration:"
msgid "Open Cashbook Wizard"
msgstr "Dialog: Kassenbuch öffnen"
msgctxt "view:cashbook.configuration:"
msgid "Cashbook"
msgstr "Kassenbuch"
msgctxt "field:cashbook.configuration,date_from:"
msgid "Start Date"
msgstr "Beginndatum"
@ -494,10 +506,34 @@ msgctxt "field:cashbook.configuration,checked:"
msgid "Checked"
msgstr "Geprüft"
msgctxt "help:cashbook.configuration,checked:"
msgid "Show cashbook lines in Checked-state."
msgstr "Zeigt Kassenbuchzeilen im 'Geprüft'-Status"
msgctxt "field:cashbook.configuration,done:"
msgid "Done"
msgstr "Fertig"
msgctxt "help:cashbook.configuration,done:"
msgid "Show cashbook lines in Done-state."
msgstr "Zeigt Kassenbuchzeilen im 'Fertig'-Status"
msgctxt "field:cashbook.configuration,catnamelong:"
msgid "Category: Show long name"
msgstr "Kategorie: langen Namen zeigen"
msgctxt "help:cashbook.configuration,catnamelong:"
msgid "Shows the long name of the category in the Category field of a cash book line."
msgstr "Zeigt im Feld 'Kategorie' einer Kassenbuchzeile den langen Namen der Kategorie."
msgctxt "field:cashbook.configuration,cataccno:"
msgid "Category: Show account number"
msgstr "Kategorie: Kontonummer zeigen"
msgctxt "help:cashbook.configuration,cataccno:"
msgid "Shows the number of the linked account in the name of a category."
msgstr "Zeigt im Namen einer Kategorie die Nummer des verknüpften Kontos."
###############################
# cashbook.configuration_user #
@ -518,6 +554,30 @@ msgctxt "field:cashbook.configuration_user,checked:"
msgid "Checked"
msgstr "Geprüft"
msgctxt "help:cashbook.configuration_user,checked:"
msgid "Show cashbook lines in Checked-state."
msgstr "Zeigt Kassenbuchzeilen im 'Geprüft'-Status"
msgctxt "field:cashbook.configuration_user,done:"
msgid "Done"
msgstr "Fertig"
msgctxt "help:cashbook.configuration_user,done:"
msgid "Show cashbook lines in Done-state."
msgstr "Zeigt Kassenbuchzeilen im 'Fertig'-Status"
msgctxt "field:cashbook.configuration_user,catnamelong:"
msgid "Category: Show long name"
msgstr "Kategorie: langen Namen zeigen"
msgctxt "help:cashbook.configuration_user,catnamelong:"
msgid "Shows the long name of the category in the Category field of a cash book line."
msgstr "Zeigt im Feld 'Kategorie' einer Kassenbuchzeile den langen Namen der Kategorie."
msgctxt "field:cashbook.configuration_user,cataccno:"
msgid "Category: Show account number"
msgstr "Kategorie: Kontonummer zeigen"
msgctxt "help:cashbook.configuration_user,cataccno:"
msgid "Shows the number of the linked account in the name of a category."
msgstr "Zeigt im Namen einer Kategorie die Nummer des verknüpften Kontos."

View file

@ -25,6 +25,10 @@ full copyright notices and license terms. -->
<field name="menu" ref="menu_config"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.ui.menu-res.group" id="menu_config-group_cashbook">
<field name="menu" ref="menu_config"/>
<field name="group" ref="group_cashbook"/>
</record>
<!-- menu: /Cashbook/Configuration/Cashbook -->
<menuitem id="menu_bookconfig" action="act_book_view"
@ -54,7 +58,7 @@ full copyright notices and license terms. -->
</record>
<!-- menu: /Cashbook/Configuration/Category/Category -->
<menuitem id="menu_category_list" action="act_category_list"
icon="tryton-tree"
icon="tryton-list"
parent="menu_category" sequence="30"/>
<record model="ir.ui.menu-res.group" id="menu_category_list-group_admin">
<field name="menu" ref="menu_category_list"/>
@ -63,7 +67,7 @@ full copyright notices and license terms. -->
<!-- menu: /Cashbook/Open Cashbook -->
<menuitem id="menu_open_lines" action="act_open_lines"
icon="tryton-tree"
icon="tryton-list"
parent="menu_cashbook" sequence="20"/>
</data>

View file

@ -35,6 +35,9 @@ full copyright notices and license terms. -->
<record model="ir.message" id="msg_category_name_unique">
<field name="text">The category name already exists at this level.</field>
</record>
<record model="ir.message" id="msg_category_account_unique">
<field name="text">The account is already in use for a category.</field>
</record>
</data>
</tryton>

View file

@ -142,7 +142,7 @@ class CategoryTestCase(ModuleTestCase):
'account': account.id,
}])
self.assertEqual(cat1.name, 'Test 1')
self.assertEqual(cat1.rec_name, '0123 Test 1')
self.assertEqual(cat1.rec_name, 'Test 1 [0123]')
self.assertEqual(cat1.description, 'Info')
self.assertEqual(cat1.company.rec_name, 'm-ds')

View file

@ -28,6 +28,8 @@ class ConfigTestCase(ModuleTestCase):
self.assertEqual(cfg2.date_to, None)
self.assertEqual(cfg2.checked, True)
self.assertEqual(cfg2.done, False)
self.assertEqual(cfg2.catnamelong, True)
self.assertEqual(cfg2.cataccno, True)
@with_transaction()
def test_config_create_multi_user(self):
@ -36,13 +38,18 @@ class ConfigTestCase(ModuleTestCase):
pool = Pool()
Configuration = pool.get('cashbook.configuration')
ResUser = pool.get('res.user')
ResGroup = pool.get('res.group')
grp_cb, = ResGroup.search([('name', '=', 'Cashbook')])
usr_lst = ResUser.create([{
'login': 'frida',
'name': 'Frida',
'groups': [('add', [grp_cb.id])],
}, {
'login': 'diego',
'name': 'Diego',
'groups': [('add', [grp_cb.id])],
}])
self.assertEqual(len(usr_lst), 2)
self.assertEqual(usr_lst[0].name, 'Frida')

View file

@ -159,6 +159,98 @@ class LineTestCase(ModuleTestCase):
IrDate.today = MagicMock(return_value=date.today())
@with_transaction()
def test_line_create_check_category_view(self):
""" create cashbook + line, check 'category_view'
"""
pool = Pool()
Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
Line = pool.get('cashbook.line')
Configuration = pool.get('cashbook.configuration')
Category = pool.get('cashbook.category')
Account = pool.get('account.account')
types, = Types.search([('short', '=','CAS')])
category = self.prep_category()
company = category.company
with Transaction().set_context({
'company': company.id,
}):
accounts = Account.create([{
'name': 'Account No 1',
'code': '0123',
}, {
'name': 'Account No 2',
'code': '2345',
}])
self.assertEqual(accounts[0].rec_name, '0123 - Account No 1')
self.assertEqual(accounts[1].rec_name, '2345 - Account No 2')
category2, = Category.create([{
'company': company.id,
'name': 'Level1',
'account': accounts[0].id,
'childs': [('create', [{
'company': company.id,
'name': 'Level2',
'account': accounts[1].id,
}])],
}])
self.assertEqual(category2.rec_name, 'Level1 [0123]')
self.assertEqual(len(category2.childs), 1)
self.assertEqual(category2.childs[0].rec_name, 'Level1/Level2 [2345]')
cfg1 = Configuration()
cfg1.save()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Text 1',
'category': category2.id,
}, {
'date': date(2022, 6, 1),
'description': 'Text 2',
'category': category2.childs[0].id,
}])],
}])
self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.state, 'open')
self.assertEqual(len(book.lines), 2)
self.assertEqual(cfg1.catnamelong, True)
self.assertEqual(cfg1.cataccno, True)
self.assertEqual(book.lines[0].category.rec_name, 'Level1 [0123]')
self.assertEqual(book.lines[1].category.rec_name, 'Level1/Level2 [2345]')
self.assertEqual(book.lines[0].category_view, 'Level1 [0123]')
self.assertEqual(book.lines[1].category_view, 'Level1/Level2 [2345]')
cfg1.cataccno = False
cfg1.save()
self.assertEqual(book.lines[0].category.rec_name, 'Level1')
self.assertEqual(book.lines[1].category.rec_name, 'Level1/Level2')
self.assertEqual(book.lines[0].category_view, 'Level1')
self.assertEqual(book.lines[1].category_view, 'Level1/Level2')
cfg1.catnamelong = False
cfg1.save()
self.assertEqual(book.lines[0].category.rec_name, 'Level1')
self.assertEqual(book.lines[1].category.rec_name, 'Level1/Level2')
self.assertEqual(book.lines[0].category_view, 'Level1')
self.assertEqual(book.lines[1].category_view, 'Level2')
cfg1.cataccno = True
cfg1.save()
self.assertEqual(book.lines[0].category.rec_name, 'Level1 [0123]')
self.assertEqual(book.lines[1].category.rec_name, 'Level1/Level2 [2345]')
self.assertEqual(book.lines[0].category_view, 'Level1 [0123]')
self.assertEqual(book.lines[1].category_view, 'Level2 [2345]')
@with_transaction()
def test_line_delete_with_book_in_open_state(self):
""" create cashbook + line, book in state=open, delete a line

View file

@ -17,6 +17,8 @@ full copyright notices and license terms. -->
<field name="company"/>
<label name="parent"/>
<field name="parent"/>
<label name="sequence"/>
<field name="sequence"/>
<field name="childs" colspan="4"/>
</page>
</notebook>

View file

@ -2,7 +2,8 @@
<!-- 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
full copyright notices and license terms. -->
<tree>
<tree sequence="sequence">
<field name="rec_name"/>
<field name="account"/>
<field name="sequence" tree_invisible="1"/>
</tree>

View file

@ -2,9 +2,10 @@
<!-- 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
full copyright notices and license terms. -->
<tree>
<tree sequence="sequence">
<field name="name"/>
<field name="account_code"/>
<field name="sequence" tree_invisible="1"/>
<field name="parent" tree_invisible="1"/>
<field name="childs" tree_invisible="1"/>
</tree>

View file

@ -11,4 +11,11 @@ this repository contains the full copyright notices and license terms. -->
<field name="checked"/>
<label name="done"/>
<field name="done"/>
<separator id="sepcb" colspan="4" string="Cashbook"/>
<label name="catnamelong"/>
<field name="catnamelong"/>
<label name="cataccno"/>
<field name="cataccno"/>
</form>

View file

@ -5,7 +5,7 @@ full copyright notices and license terms. -->
<tree>
<field name="cashbook"/>
<field name="date"/>
<field name="category"/>
<field name="category_view"/>
<field name="description"/>
<field name="state"/>
<button name="wfedit"/>