From 01470569e7ccb3469d00c0300aa180a81868d46a Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Sat, 29 Oct 2022 23:05:27 +0200 Subject: [PATCH] =?UTF-8?q?cashbooks,=20types,=20currenciews=20-=20verkn?= =?UTF-8?q?=C3=BCpfung+l=C3=B6schen+test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __init__.py | 5 +- evaluation.py | 119 +++++++++++++++++++++++-- locale/de.po | 54 +++++++++++- locale/en.po | 64 ++++++++++++++ message.xml | 16 ++++ tests/test_report.py | 184 ++++++++++++++++++++++++++++++++++++--- tryton.cfg | 1 + view/evaluation_form.xml | 7 +- view/evaluation_list.xml | 1 - 9 files changed, 429 insertions(+), 22 deletions(-) create mode 100644 message.xml diff --git a/__init__.py b/__init__.py index 7f0fd4a..660f817 100644 --- a/__init__.py +++ b/__init__.py @@ -4,10 +4,13 @@ # full copyright notices and license terms. from trytond.pool import Pool -from .evaluation import Evaluation, EvaluationCashbookRel +from .evaluation import Evaluation, EvaluationCashbookRel, \ + EvaluationTypeRel, EvaluationCurrencyRel def register(): Pool.register( Evaluation, EvaluationCashbookRel, + EvaluationTypeRel, + EvaluationCurrencyRel, module='cashbook_report', type_='model') diff --git a/evaluation.py b/evaluation.py index a7edb3d..01efe91 100644 --- a/evaluation.py +++ b/evaluation.py @@ -6,13 +6,16 @@ from trytond.model import ModelView, ModelSQL, fields, Check from trytond.pyson import Eval, Or, Bool, Id, Len from trytond.transaction import Transaction +from trytond.i18n import gettext +from trytond.exceptions import UserError from .colors import sel_color as sel_bgcolor sel_etype = [ - ('book', 'Cashbooks'), - ('type', 'Types of Cashbooks'), - ('currency', 'Currencys'), + ('cashbooks', 'Cashbooks'), + ('types', 'Types of Cashbooks'), + ('currencies', 'Currencys'), + #('category', 'Category'), ] sel_chart = [ @@ -54,9 +57,28 @@ class Evaluation(ModelSQL, ModelView): help='Background color of the chart area.', sort=False, selection=sel_bgcolor) posted = fields.Boolean(string='Posted', help='Posted amounts only.') - lines = fields.Many2Many(string='Cashbooks', + + cashbooks = fields.Many2Many(string='Cashbooks', relation_name='cashbook_report.eval_book', - origin='evaluation', target='cashbook') + origin='evaluation', target='cashbook', + states={ + 'invisible': Eval('dtype', '') != 'cashbooks', + }, depends=['dtype']) + types = fields.Many2Many(string='Types', + relation_name='cashbook_report.eval_type', + origin='evaluation', target='dtype', + states={ + 'invisible': Eval('dtype', '') != 'types', + }, depends=['dtype']) + currencies = fields.Many2Many(string='Currencies', + relation_name='cashbook_report.eval_currency', + origin='evaluation', target='currency', + states={ + 'invisible': Eval('dtype', '') != 'currencies', + }, depends=['dtype']) + + values = fields.One2Many(string='Values', field='evaluation', + model_name='cashbook_report.eval_book', readonly=True) @staticmethod def default_company(): @@ -90,7 +112,7 @@ class Evaluation(ModelSQL, ModelView): def default_dtype(cls): """ default 'book' """ - return 'book' + return 'cashbooks' @classmethod def default_chart(cls): @@ -98,6 +120,50 @@ class Evaluation(ModelSQL, ModelView): """ return 'pie' + @classmethod + def write(cls, *args): + """ unlink records if dtype changes + """ + to_write = [] + actions = iter(args) + for evaluations, values in zip(actions, actions): + if 'dtype' in values.keys(): + for evaluation in evaluations: + if evaluation.dtype == values['dtype']: + continue + + if (values['dtype'] != 'cashbooks') and \ + (len(evaluation.cashbooks) > 0): + to_write.extend([ + [evaluation], + { + 'cashbooks': [ + ('remove', [x.id for x in evaluation.cashbooks]) + ], + }]) + + if (values['dtype'] != 'types') and (len(evaluation.types) > 0): + to_write.extend([ + [evaluation], + { + 'types': [ + ('remove', [x.id for x in evaluation.types]) + ], + }]) + + if (values['dtype'] != 'currencies') and (len(evaluation.currencies) > 0): + to_write.extend([ + [evaluation], + { + 'currencies': [ + ('remove', [x.id for x in evaluation.currencies]) + ], + }]) + + args = list(args) + args.extend(to_write) + super(Evaluation, cls).write(*args) + # end Evaluation @@ -112,4 +178,45 @@ class EvaluationCashbookRel(ModelSQL): select=True, ondelete='CASCADE', model_name='cashbook.book') + @classmethod + def validate(cls, records): + """ check parent record + """ + super(EvaluationCashbookRel, cls).validate(records) + + for record in records: + if record.evaluation.dtype != 'cashbooks': + raise UserError(gettext( + 'cashbook_report.msg_invalid_dtype', + dtype = gettext('cashbook_report.msg_dtype_cashbook'), + )) + # end EvaluationCashbookRel + + +class EvaluationTypeRel(ModelSQL): + 'Evaluation Type Relation' + __name__ = 'cashbook_report.eval_type' + + evaluation = fields.Many2One(string='Evaluation', required=True, + select=True, ondelete='CASCADE', + model_name='cashbook_report.evaluation') + dtype = fields.Many2One(string='Type', required=True, + select=True, ondelete='CASCADE', + model_name='cashbook.type') + +# end EvaluationTypeRel + + +class EvaluationCurrencyRel(ModelSQL): + 'Evaluation Currency Relation' + __name__ = 'cashbook_report.eval_currency' + + evaluation = fields.Many2One(string='Evaluation', required=True, + select=True, ondelete='CASCADE', + model_name='cashbook_report.evaluation') + currency = fields.Many2One(string='Currency', required=True, + select=True, ondelete='CASCADE', + model_name='currency.currency') + +# end EvaluationCurrencyRel diff --git a/locale/de.po b/locale/de.po index 7b25302..fbbf608 100644 --- a/locale/de.po +++ b/locale/de.po @@ -3,6 +3,18 @@ msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" +############## +# ir.message # +############## +msgctxt "model:ir.message,text:msg_name_cashbook" +msgid "Type of evaluation must be '%(dtype)s'." +msgstr "Typ der Auswertung mus '%(dtype)s' sein." + +msgctxt "model:ir.message,text:msg_dtype_cashbook" +msgid "Cashbooks" +msgstr "Kassenbücher" + + ################# # ir.rule.group # ################# @@ -43,6 +55,38 @@ msgid "Cashbook" msgstr "Kassenbuch" +############################# +# cashbook_report.eval_type # +############################# +msgctxt "model:cashbook_report.eval_type,name:" +msgid "Evaluation Type Relation" +msgstr "Auswertung Typ Verknüpfung" + +msgctxt "field:cashbook_report.eval_type,evaluation:" +msgid "Evaluation" +msgstr "Auswertung" + +msgctxt "field:cashbook_report.eval_type,dtype:" +msgid "Type" +msgstr "Typ" + + +################################# +# cashbook_report.eval_currency # +################################# +msgctxt "model:cashbook_report.eval_currency,name:" +msgid "Evaluation Currency Relation" +msgstr "Auswertung Währung Verknüpfung" + +msgctxt "field:cashbook_report.eval_currency,evaluation:" +msgid "Evaluation" +msgstr "Auswertung" + +msgctxt "field:cashbook_report.eval_currency,currency:" +msgid "Currency" +msgstr "Währung" + + ############################## # cashbook_report.evaluation # ############################## @@ -162,6 +206,14 @@ msgctxt "help:cashbook_report.evaluation,posted:" msgid "Posted amounts only." msgstr "Nur festgeschriebene Beträge." -msgctxt "field:cashbook_report.evaluation,lines:" +msgctxt "field:cashbook_report.evaluation,cashbooks:" msgid "Cashbooks" msgstr "Kassenbücher" + +msgctxt "field:cashbook_report.evaluation,types:" +msgid "Types" +msgstr "Typen" + +msgctxt "field:cashbook_report.evaluation,currencies:" +msgid "Currencies" +msgstr "Währungen" diff --git a/locale/en.po b/locale/en.po index afb24b8..c26ba5d 100644 --- a/locale/en.po +++ b/locale/en.po @@ -2,6 +2,14 @@ msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" +msgctxt "model:ir.message,text:msg_name_cashbook" +msgid "Type of evaluation must be '%(dtype)s'." +msgstr "Type of evaluation must be '%(dtype)s'." + +msgctxt "model:ir.message,text:msg_dtype_cashbook" +msgid "Cashbooks" +msgstr "Cashbooks" + msgctxt "model:ir.rule.group,name:rg_eval_write_adm" msgid "Administrators: Evaluation read/write" msgstr "Administrators: Evaluation read/write" @@ -18,10 +26,54 @@ msgctxt "model:ir.ui.menu,name:menu_evaluation" msgid "Evaluation" msgstr "Evaluation" +msgctxt "model:cashbook_report.eval_book,name:" +msgid "Evaluation Cashbook Relation" +msgstr "Evaluation Cashbook Relation" + +msgctxt "field:cashbook_report.eval_book,evaluation:" +msgid "Evaluation" +msgstr "Evaluation" + +msgctxt "field:cashbook_report.eval_book,cashbook:" +msgid "Cashbook" +msgstr "Cashbook" + +msgctxt "model:cashbook_report.eval_type,name:" +msgid "Evaluation Type Relation" +msgstr "Evaluation Type Relation" + +msgctxt "field:cashbook_report.eval_type,evaluation:" +msgid "Evaluation" +msgstr "Evaluation" + +msgctxt "field:cashbook_report.eval_type,dtype:" +msgid "Type" +msgstr "Type" + +msgctxt "model:cashbook_report.eval_currency,name:" +msgid "Evaluation Currency Relation" +msgstr "Evaluation Currency Relation" + +msgctxt "field:cashbook_report.eval_currency,evaluation:" +msgid "Evaluation" +msgstr "Evaluation" + +msgctxt "field:cashbook_report.eval_currency,currency:" +msgid "Currency" +msgstr "Currency" + msgctxt "model:cashbook_report.evaluation,name:" msgid "Evaluation" msgstr "Evaluation" +msgctxt "view:cashbook_report.evaluation:" +msgid "Chart" +msgstr "Chart" + +msgctxt "view:cashbook_report.evaluation:" +msgid "Settings" +msgstr "Settings" + msgctxt "view:cashbook_report.evaluation:" msgid "Representation" msgstr "Representation" @@ -122,3 +174,15 @@ msgctxt "field:cashbook_report.evaluation,posted:" msgid "Posted" msgstr "Posted" +msgctxt "help:cashbook_report.evaluation,posted:" +msgid "Posted amounts only." +msgstr "Posted amounts only." + +msgctxt "field:cashbook_report.evaluation,cashbooks:" +msgid "Cashbooks" +msgstr "Cashbooks" + +msgctxt "field:cashbook_report.evaluation,types:" +msgid "Types" +msgstr "Types" + diff --git a/message.xml b/message.xml new file mode 100644 index 0000000..29da0b2 --- /dev/null +++ b/message.xml @@ -0,0 +1,16 @@ + + + + + + + Type of evaluation must be '%(dtype)s'. + + + Cashbooks + + + + diff --git a/tests/test_report.py b/tests/test_report.py index a03f27d..69711c2 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -22,16 +22,18 @@ class ReportTestCase(CashbookTestCase): pool = Pool() Book = pool.get('cashbook.book') - types = self.prep_type() + type_cash = self.prep_type() + type_bank = self.prep_type(name='Bank', short='BK') company = self.prep_company() + (usd, euro) = self.prep_2nd_currency(company) sequ_id = self.prep_sequence().id category = self.prep_category(cattype='in') party = self.prep_party() books = Book.create([{ 'name': 'Book 1', - 'btype': types.id, + 'btype': type_cash.id, 'company': company.id, - 'currency': company.currency.id, + 'currency': usd.id, 'number_sequ': sequ_id, 'start_date': date(2022, 4, 1), 'lines': [('create', [{ @@ -51,9 +53,9 @@ class ReportTestCase(CashbookTestCase): }])], }, { 'name': 'Book 2', - 'btype': types.id, + 'btype': type_cash.id, 'company': company.id, - 'currency': company.currency.id, + 'currency': usd.id, 'number_sequ': sequ_id, 'start_date': date(2022, 4, 1), 'lines': [('create', [{ @@ -73,9 +75,9 @@ class ReportTestCase(CashbookTestCase): }])], }, { 'name': 'Book 3', - 'btype': types.id, + 'btype': type_bank.id, 'company': company.id, - 'currency': company.currency.id, + 'currency': euro.id, 'number_sequ': sequ_id, 'start_date': date(2022, 4, 1), 'lines': [('create', [{ @@ -96,22 +98,120 @@ class ReportTestCase(CashbookTestCase): }]) self.assertEqual(len(books), 3) self.assertEqual(books[0].name, 'Book 1') + self.assertEqual(books[0].btype.rec_name, 'CAS - Cash') self.assertEqual(len(books[0].lines), 2) self.assertEqual(books[0].balance, Decimal('25.0')) self.assertEqual(books[1].name, 'Book 2') + self.assertEqual(books[1].btype.rec_name, 'CAS - Cash') self.assertEqual(len(books[1].lines), 2) self.assertEqual(books[1].balance, Decimal('12.5')) self.assertEqual(books[2].name, 'Book 3') + self.assertEqual(books[2].btype.rec_name, 'BK - Bank') self.assertEqual(len(books[2].lines), 2) self.assertEqual(books[2].balance, Decimal('23.0')) return books + @with_transaction() + def test_report_dtype_update(self): + """ check unlink of cashbooks/types/currenciews + """ + pool = Pool() + Evaluation = pool.get('cashbook_report.evaluation') + Types = pool.get('cashbook.type') + Currency = pool.get('currency.currency') + + books = self.prep_report_3books() + + company = self.prep_company() + with Transaction().set_context({ + 'company': company.id, + }): + # valid + evaluation, = Evaluation.create([{ + 'name': 'Evaluation 1', + 'dtype': 'cashbooks', + 'cashbooks': [('add', [x.id for x in books])], + }]) + self.assertEqual(len(evaluation.cashbooks), 3) + self.assertEqual(len(evaluation.types), 0) + self.assertEqual(len(evaluation.currencies), 0) + + Evaluation.write(*[ + [evaluation], + { + 'dtype': 'types', + 'types': [('add', [x.id for x in Types.search([])])], + }]) + self.assertEqual(len(evaluation.cashbooks), 0) + self.assertEqual(len(evaluation.types), 2) + self.assertEqual(len(evaluation.currencies), 0) + + # write same dtype again - no change + Evaluation.write(*[ + [evaluation], + { + 'dtype': 'types', + }]) + self.assertEqual(len(evaluation.cashbooks), 0) + self.assertEqual(len(evaluation.types), 2) + self.assertEqual(len(evaluation.currencies), 0) + + Evaluation.write(*[ + [evaluation], + { + 'dtype': 'currencies', + 'currencies': [('add', [x.id for x in Currency.search([])])], + }]) + self.assertEqual(len(evaluation.cashbooks), 0) + self.assertEqual(len(evaluation.types), 0) + self.assertEqual(len(evaluation.currencies), 2) + + Evaluation.write(*[ + [evaluation], + { + 'dtype': 'cashbooks', + }]) + self.assertEqual(len(evaluation.cashbooks), 0) + self.assertEqual(len(evaluation.types), 0) + self.assertEqual(len(evaluation.currencies), 0) + + @with_transaction() + def test_report_dtype_validation(self): + """ check validation of dtype + """ + pool = Pool() + Evaluation = pool.get('cashbook_report.evaluation') + Types = pool.get('cashbook.type') + + books = self.prep_report_3books() + + company = self.prep_company() + with Transaction().set_context({ + 'company': company.id, + }): + # valid + evaluation, = Evaluation.create([{ + 'name': 'Evaluation 1', + 'dtype': 'cashbooks', + 'cashbooks': [('add', [x.id for x in books])], + }]) + + # must fail + self.assertRaisesRegex(UserError, + "Type of evaluation must be 'Cashbooks'.", + Evaluation.create, + [{ + 'name': 'Evaluation 1', + 'dtype': 'types', # wrong dtype + 'cashbooks': [('add', [x.id for x in books])], + }]) + @with_transaction() def test_report_chart_pie_book_red(self): """ create 3x cashbooks, add bookings, - create report, check + create report with cashbooks, check """ Evaluation = Pool().get('cashbook_report.evaluation') @@ -123,14 +223,76 @@ class ReportTestCase(CashbookTestCase): }): evaluation, = Evaluation.create([{ 'name': 'Evaluation 1', - 'lines': [('add', [x.id for x in books])], + 'cashbooks': [('add', [x.id for x in books])], }]) - self.assertEqual(len(evaluation.lines), 3) - self.assertEqual(evaluation.dtype, 'book') + self.assertEqual(evaluation.dtype, 'cashbooks') self.assertEqual(evaluation.chart, 'pie') self.assertEqual(evaluation.legend, True) self.assertEqual(evaluation.posted, False) self.assertEqual(evaluation.maincolor, 'default') self.assertEqual(evaluation.bgcolor, '#ffffc0') + self.assertEqual(len(evaluation.cashbooks), 3) + self.assertEqual(evaluation.cashbooks[0].rec_name, 'Book 1 | 25.00 usd | Open') + self.assertEqual(evaluation.cashbooks[1].rec_name, 'Book 2 | 12.50 usd | Open') + self.assertEqual(evaluation.cashbooks[2].rec_name, 'Book 3 | 23.00 € | Open') + + @with_transaction() + def test_report_chart_pie_type_red(self): + """ create 3x cashbooks, add bookings, + create report with types of cashbooks, check + """ + pool = Pool() + Evaluation = pool.get('cashbook_report.evaluation') + Types = pool.get('cashbook.type') + + books = self.prep_report_3books() + + company = self.prep_company() + with Transaction().set_context({ + 'company': company.id, + }): + evaluation, = Evaluation.create([{ + 'name': 'Evaluation 1', + 'dtype': 'types', + 'types': [('add', [x.id for x in Types.search([])])], + }]) + self.assertEqual(evaluation.dtype, 'types') + self.assertEqual(evaluation.chart, 'pie') + self.assertEqual(evaluation.legend, True) + self.assertEqual(evaluation.posted, False) + self.assertEqual(evaluation.maincolor, 'default') + self.assertEqual(evaluation.bgcolor, '#ffffc0') + + self.assertEqual(len(evaluation.types), 2) + + @with_transaction() + def test_report_chart_pie_currency_red(self): + """ create 3x cashbooks, add bookings, + create report with types of cashbooks, check + """ + pool = Pool() + Evaluation = pool.get('cashbook_report.evaluation') + Currency = pool.get('currency.currency') + + books = self.prep_report_3books() + + company = self.prep_company() + with Transaction().set_context({ + 'company': company.id, + }): + evaluation, = Evaluation.create([{ + 'name': 'Evaluation 1', + 'dtype': 'currencies', + 'currencies': [('add', [x.id for x in Currency.search([])])], + }]) + self.assertEqual(evaluation.dtype, 'currencies') + self.assertEqual(evaluation.chart, 'pie') + self.assertEqual(evaluation.legend, True) + self.assertEqual(evaluation.posted, False) + self.assertEqual(evaluation.maincolor, 'default') + self.assertEqual(evaluation.bgcolor, '#ffffc0') + + self.assertEqual(len(evaluation.currencies), 2) + # end ReportTestCase diff --git a/tryton.cfg b/tryton.cfg index e1814a4..04a291e 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -4,6 +4,7 @@ depends: cashbook xml: icon.xml + message.xml graph.xml evaluation.xml menu.xml diff --git a/view/evaluation_form.xml b/view/evaluation_form.xml index 6560e0e..e7b804b 100644 --- a/view/evaluation_form.xml +++ b/view/evaluation_form.xml @@ -5,7 +5,8 @@ full copyright notices and license terms. -->
- + +
diff --git a/view/evaluation_list.xml b/view/evaluation_list.xml index 0dff23b..d22a14c 100644 --- a/view/evaluation_list.xml +++ b/view/evaluation_list.xml @@ -8,5 +8,4 @@ full copyright notices and license terms. --> -