From 8fd6e0d3397905d396daae85401d14060e0f0445 Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Thu, 11 Aug 2022 11:06:28 +0200 Subject: [PATCH] =?UTF-8?q?kategorie:=20sperrt=20'Typ'=20wenn=20parent=20e?= =?UTF-8?q?xistiert,=20korrekte=20Anpassung=20=20der=20sub-kategorien=20be?= =?UTF-8?q?i=20=C3=84nderung=20+=20test=20Line:=20Kategoriefeld=20pr=C3=BC?= =?UTF-8?q?ft=20Inhalt=20+=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- category.py | 68 ++++++++++++++++++++++++++++++++---------- line.py | 9 ++++-- tests/test_book.py | 6 ++-- tests/test_category.py | 50 ++++++++++++++++++++++++++++++- tests/test_line.py | 40 ++++++++++++------------- view/category_form.xml | 2 +- view/line_form.xml | 8 ++--- 7 files changed, 137 insertions(+), 46 deletions(-) diff --git a/category.py b/category.py index c4d9ac8..661c780 100644 --- a/category.py +++ b/category.py @@ -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 diff --git a/line.py b/line.py index 40d6f6f..ee559c7 100644 --- a/line.py +++ b/line.py @@ -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']), diff --git a/tests/test_book.py b/tests/test_book.py index 0db06ec..29a90f3 100644 --- a/tests/test_book.py +++ b/tests/test_book.py @@ -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', diff --git a/tests/test_category.py b/tests/test_category.py index f4a7325..39759a1 100644 --- a/tests/test_category.py +++ b/tests/test_category.py @@ -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 diff --git a/tests/test_line.py b/tests/test_line.py index 5f7d905..63c644f 100644 --- a/tests/test_line.py +++ b/tests/test_line.py @@ -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([{ diff --git a/view/category_form.xml b/view/category_form.xml index baa4999..c06201b 100644 --- a/view/category_form.xml +++ b/view/category_form.xml @@ -23,7 +23,7 @@ full copyright notices and license terms. -->