kategorie: sperrt 'Typ' wenn parent existiert, korrekte Anpassung

der sub-kategorien bei Änderung + test
Line: Kategoriefeld prüft Inhalt + tests
This commit is contained in:
Frederik Jaeckel 2022-08-11 11:06:28 +02:00
parent 52ffa0536e
commit 8fd6e0d339
7 changed files with 137 additions and 46 deletions

View file

@ -6,6 +6,7 @@
from trytond.model import ModelView, ModelSQL, fields, Unique, tree, sequence_ordered
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
@ -23,7 +24,15 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
name = fields.Char(string='Name', required=True, translate=True)
description = fields.Char(string='Description', translate=True)
cattype = fields.Selection(string='Type', required=True,
help='Type of Category', selection=sel_categorytype)
help='Type of Category', selection=sel_categorytype,
states={'readonly': Bool(Eval('parent_cattype'))},
domain=[If(Bool(Eval('parent_cattype')),
('cattype', '=', Eval('parent_cattype', '')),
())],
depends=['parent_cattype'])
parent_cattype = fields.Function(fields.Char(string='Parent Category Type',
readonly=True, states={'invisible': True}),
'on_change_with_parent_cattype')
account = fields.Many2One(string='Account', select=True,
model_name='account.account', ondelete='RESTRICT')
@ -98,6 +107,13 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
('account.code',) + tuple(clause[1:]),
]
@fields.depends('parent', '_parent_parent.cattype')
def on_change_with_parent_cattype(self, name=None):
""" get type of parent category or None
"""
if self.parent:
return self.parent.cattype
@fields.depends('account')
def on_change_with_account_code(self, name=None):
""" get code of account
@ -111,34 +127,56 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
"""
return [('account.code',) + tuple(clause[1:])]
@classmethod
def check_category_hierarchy(cls, categories):
""" check if current category-type is equal to parent
"""
for category in categories:
if category.parent:
if category.parent.cattype != category.cattype:
raise UserError(gettext(
'cashbook.msg_category_type_not_like_parent',
parentname = category.parent.rec_name,
catname = category.rec_name,
))
@classmethod
def create(cls, vlist):
""" add debit/credit
"""
records = super(Category, cls).create(vlist)
cls.check_category_hierarchy(records)
return records
@classmethod
def write(cls, *args):
""" parent.cattape == cattype,
update sub-categories
"""
to_write = []
actions = iter(args)
to_check = []
to_write = []
to_write2 = []
for categories, values in zip(actions, actions):
to_write2.extend([categories, values])
if 'cattype' in values.keys():
for category in categories:
if category.parent:
if category.parent.cattype != values['cattype']:
raise UserError(gettext(
'cashbook.msg_category_type_not_like_parent',
parentname = category.parent.rec_name,
catname = category.rec_name,
))
cats = Category.search([('parent', 'child_of', [x.id for x in categories])])
# update sub-categories
cats = Category.search([
('parent', 'child_of', [x.id for x in categories])
])
if len(cats) > 0:
to_write.extend([
cats,
{
'cattype': values['cattype'],
}])
to_check.extend(categories)
to_check.extend(cats)
super(Category, cls).write(*args)
if len(to_write) > 0:
print('\n## to_write:',to_write)
Category.write(*to_write)
# add category-updates after regulary writes
to_write2.extend(to_write)
super(Category, cls).write(*to_write2)
cls.check_category_hierarchy(to_check)
# end Category

View file

@ -5,7 +5,7 @@
from trytond.model import ModelView, ModelSQL, Workflow, fields, Check
from trytond.pool import Pool
from trytond.pyson import Eval, If, Or
from trytond.pyson import Eval, If, Or, Bool
from trytond.transaction import Transaction
from trytond.report import Report
from trytond.exceptions import UserError
@ -53,7 +53,12 @@ class Line(Workflow, ModelSQL, ModelView):
states=STATES, depends=DEPENDS)
category = fields.Many2One(string='Category', required=True,
model_name='cashbook.category', ondelete='RESTRICT',
states=STATES, depends=DEPENDS+['bookingtype'],
states={
'readonly': Or(
STATES['readonly'],
Bool(Eval('bookingtype')) == False,
),
}, depends=DEPENDS+['bookingtype'],
domain=[
If(
Eval('bookingtype', '').in_(['in', 'mvin']),

View file

@ -43,7 +43,7 @@ class BookTestCase(ModuleTestCase):
Book = pool.get('cashbook.book')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
book, = Book.create([{
'name': 'Book 1',
@ -74,7 +74,7 @@ class BookTestCase(ModuleTestCase):
Book = pool.get('cashbook.book')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
book, = Book.create([{
'name': 'Book 1',
@ -107,7 +107,7 @@ class BookTestCase(ModuleTestCase):
Book = pool.get('cashbook.book')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
book, = Book.create([{
'name': 'Book 1',

View file

@ -13,7 +13,7 @@ class CategoryTestCase(ModuleTestCase):
'Test cashbook categoy module'
module = 'cashbook'
def prep_category(self, name='Cat1'):
def prep_category(self, name='Cat1', cattype='out'):
""" create category
"""
pool = Pool()
@ -24,9 +24,57 @@ class CategoryTestCase(ModuleTestCase):
category, = Category.create([{
'company': company.id,
'name': name,
'cattype': cattype,
}])
return category
@with_transaction()
def test_category_create_check_category_type(self):
""" create category, update type of category
"""
pool = Pool()
Category = pool.get('cashbook.category')
company = self.prep_company()
category, = Category.create([{
'company': company.id,
'name': 'Level 1',
'cattype': 'in',
'childs': [('create', [{
'company': company.id,
'name': 'Level 2',
'cattype': 'in',
}])],
}])
self.assertEqual(category.rec_name, 'Level 1')
self.assertEqual(category.cattype, 'in')
self.assertEqual(len(category.childs), 1)
self.assertEqual(category.childs[0].rec_name, 'Level 1/Level 2')
self.assertEqual(category.childs[0].cattype, 'in')
self.assertRaisesRegex(UserError,
'The value for field "Type" in "Category" is not valid according to its domain.',
Category.write,
*[
[category.childs[0]],
{
'cattype': 'out',
},
])
Category.write(*[
[category],
{
'cattype': 'out',
}])
self.assertEqual(category.rec_name, 'Level 1')
self.assertEqual(category.cattype, 'out')
self.assertEqual(len(category.childs), 1)
self.assertEqual(category.childs[0].rec_name, 'Level 1/Level 2')
self.assertEqual(category.childs[0].cattype, 'out')
@with_transaction()
def test_category_create_nodupl_at_root(self):
""" create category, duplicates are allowed at root-level

View file

@ -25,7 +25,7 @@ class LineTestCase(ModuleTestCase):
Lines = pool.get('cashbook.line')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
book, = Book.create([{
'name': 'Book 1',
@ -102,7 +102,7 @@ class LineTestCase(ModuleTestCase):
Line = pool.get('cashbook.line')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
book, = Book.create([{
'name': 'Book 1',
@ -150,7 +150,7 @@ class LineTestCase(ModuleTestCase):
IrDate = pool.get('ir.date')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
IrDate.today = MagicMock(return_value=date(2022, 6, 1))
@ -214,14 +214,10 @@ class LineTestCase(ModuleTestCase):
Category = pool.get('cashbook.category')
types = self.prep_type()
category = self.prep_category()
category_in = self.prep_category(cattype='in')
category_out = self.prep_category(name='Out Category', cattype='out')
company = self.prep_company()
category2, = Category.create([{
'company': company.id,
'name': 'Category',
}])
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
@ -230,25 +226,25 @@ class LineTestCase(ModuleTestCase):
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Revenue',
'category': category2.id,
'category': category_in.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, {
'date': date(2022, 6, 1),
'description': 'Expense',
'category': category2.id,
'category': category_out.id,
'bookingtype': 'out',
'amount': Decimal('1.0'),
}, {
'date': date(2022, 6, 1),
'description': 'Transfer from',
'category': category2.id,
'category': category_in.id,
'bookingtype': 'mvin',
'amount': Decimal('1.0'),
}, {
'date': date(2022, 6, 1),
'description': 'Transfer to',
'category': category2.id,
'category': category_out.id,
'bookingtype': 'mvout',
'amount': Decimal('1.0'),
}])],
@ -291,6 +287,7 @@ class LineTestCase(ModuleTestCase):
[book.lines[0]],
{
'bookingtype': 'out',
'category': category_out.id,
}])
self.assertEqual(book.lines[0].amount, Decimal('2.0'))
self.assertEqual(book.lines[0].bookingtype, 'out')
@ -300,6 +297,7 @@ class LineTestCase(ModuleTestCase):
Line.write(*[
[book.lines[0]],
{
'category': category_in.id,
'bookingtype': 'mvin',
'amount': Decimal('3.0'),
}])
@ -320,7 +318,7 @@ class LineTestCase(ModuleTestCase):
Account = pool.get('account.account')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
with Transaction().set_context({
@ -340,10 +338,12 @@ class LineTestCase(ModuleTestCase):
'company': company.id,
'name': 'Level1',
'account': accounts[0].id,
'cattype': 'in',
'childs': [('create', [{
'company': company.id,
'name': 'Level2',
'account': accounts[1].id,
'cattype': 'in',
}])],
}])
self.assertEqual(category2.rec_name, 'Level1 [0123]')
@ -414,7 +414,7 @@ class LineTestCase(ModuleTestCase):
Lines = pool.get('cashbook.line')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
book, = Book.create([{
'name': 'Book 1',
@ -450,7 +450,7 @@ class LineTestCase(ModuleTestCase):
Lines = pool.get('cashbook.line')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
book, = Book.create([{
'name': 'Book 1',
@ -491,7 +491,7 @@ class LineTestCase(ModuleTestCase):
Lines = pool.get('cashbook.line')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
book, = Book.create([{
'name': 'Book 1',
@ -536,7 +536,7 @@ class LineTestCase(ModuleTestCase):
Line = pool.get('cashbook.line')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
usr_lst = ResUser.create([{
@ -606,7 +606,7 @@ class LineTestCase(ModuleTestCase):
Line = pool.get('cashbook.line')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
grp_reviewer, = ResGroup.create([{
@ -690,7 +690,7 @@ class LineTestCase(ModuleTestCase):
Line = pool.get('cashbook.line')
types = self.prep_type()
category = self.prep_category()
category = self.prep_category(cattype='in')
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
grp_observer, = ResGroup.create([{

View file

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

View file

@ -17,12 +17,12 @@ full copyright notices and license terms. -->
<label name="date"/>
<field name="date"/>
<label name="category"/>
<field name="category"/>
<newline/>
<label name="bookingtype"/>
<field name="bookingtype"/>
<newline/>
<label name="category"/>
<field name="category"/>
<label name="amount"/>
<field name="amount" symbol="currency"/>