diff --git a/evaluation.py b/evaluation.py index e72d43b..a25238a 100644 --- a/evaluation.py +++ b/evaluation.py @@ -15,7 +15,7 @@ sel_etype = [ ('cashbooks', 'Cashbooks'), ('types', 'Types of Cashbooks'), ('currencies', 'Currencys'), - #('category', 'Category'), + ('categories', 'Categories'), ] sel_chart = [ @@ -79,6 +79,12 @@ class Evaluation(sequence_ordered(), ModelSQL, ModelView): states={ 'invisible': Eval('dtype', '') != 'currencies', }, depends=['dtype']) + categories = fields.Many2Many(string='Categories', + relation_name='cashbook_report.eval_line', + origin='evaluation', target='category', + states={ + 'invisible': Eval('dtype', '') != 'categories', + }, depends=['dtype']) line_values = fields.One2Many(string='Line Values', field='evaluation', readonly=True, @@ -278,33 +284,16 @@ class Evaluation(sequence_ordered(), ModelSQL, ModelView): 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]) - ], - }]) + for dt in ['cashbooks', 'types', 'currencies', 'categories']: + if (values['dtype'] != dt) and \ + (len(getattr(evaluation, dt)) > 0): + to_write.extend([ + [evaluation], + { + dt: [ + ('remove', [x.id for x in getattr(evaluation, dt)]) + ], + }]) args = list(args) args.extend(to_write) diff --git a/line.py b/line.py index 02eb4ba..78c9860 100644 --- a/line.py +++ b/line.py @@ -35,6 +35,11 @@ class EvaluationLine(ModelSQL, ModelView): states={ 'required': Eval('eval_dtype', '') == 'currencies', }, depends=['eval_dtype']) + category = fields.Many2One(string='Category', select=True, ondelete='CASCADE', + model_name='cashbook.bookcategory', + states={ + 'required': Eval('eval_dtype', '') == 'categories', + }, depends=['eval_dtype']) # dtype + currency of evaluation eval_dtype = fields.Function(fields.Char(string='Data type', readonly=True), @@ -111,7 +116,7 @@ class EvaluationLine(ModelSQL, ModelView): else: return 2 - @fields.depends('eval_dtype', 'cashbook', 'dtype', 'currency', 'name_line') + @fields.depends('eval_dtype', 'category', 'cashbook', 'dtype', 'currency', 'name_line') def on_change_with_name(self, name=None): """ get name of Type """ @@ -125,6 +130,7 @@ class EvaluationLine(ModelSQL, ModelView): return getattr( getattr(self, { 'cashbooks': 'cashbook', + 'categories': 'category', 'types': 'dtype', 'currencies': 'currency', }[self.eval_dtype], None), @@ -155,45 +161,23 @@ class EvaluationLine(ModelSQL, ModelView): typename = gettext('cashbook_report.msg_dtype_currency'), )) - def get_value_cashbooks(self): - """ balance of cashbooks - """ - Currency = Pool().get('currency.currency') - - if self.cashbook: - exp = Decimal(Decimal(1) / 10 ** self.currency_digits) - return Currency.compute( - self.cashbook.currency, - self.cashbook.balance, - self.eval_currency, - ).quantize(exp) - - def get_value_types(self): - """ get balance of bookings in cashbooks by 'type', - converted to currency of evaluation + def get_balance_by_query(self, query): + """ run 'query' on Lines, convert used + currencies to evaluation-currency """ pool = Pool() Lines = pool.get('cashbook.line') Cashbook = pool.get('cashbook.book') Currency = pool.get('currency.currency') - IrDate = pool.get('ir.date') tab_line = Lines.__table__() tab_book = Cashbook.__table__() cursor = Transaction().connection.cursor() - if (self.evaluation is None) or (self.dtype is None) or \ - (self.eval_currency is None) or (self.currency_digits is None): - return None - total_amount = Decimal('0.0') with Transaction().set_context({ '_check_access': True, }): - lines = Lines.search([ - ('cashbook.btype.id', '=', self.dtype.id), - ('cashbook.state', '=', 'open'), - ('date', '<=', IrDate.today()), - ], query=True) + lines = Lines.search(query, query=True) query = lines.join(tab_line, condition=lines.id==tab_line.id, ).join(tab_book, condition=tab_book.id==tab_line.cashbook, @@ -216,57 +200,74 @@ class EvaluationLine(ModelSQL, ModelView): exp = Decimal(Decimal(1) / 10 ** self.currency_digits) return total_amount.quantize(exp) + def get_value_cashbooks(self): + """ balance of cashbooks + """ + Currency = Pool().get('currency.currency') + + if self.cashbook: + exp = Decimal(Decimal(1) / 10 ** self.currency_digits) + return Currency.compute( + self.cashbook.currency, + self.cashbook.balance, + self.eval_currency, + ).quantize(exp) + + def get_value_categories(self): + """ get balance of bookings in categories + converted to currency of evaluation + """ + IrDate = Pool().get('ir.date') + + if self.category is None: + return None + + return self.get_balance_by_query([ + ('cashbook.categories.id', '=', self.category.id), + ('cashbook.state', '=', 'open'), + ('date', '<=', IrDate.today()), + ]) + + def get_value_types(self): + """ get balance of bookings in cashbooks by 'type', + converted to currency of evaluation + """ + IrDate = Pool().get('ir.date') + + if self.dtype is None: + return None + + return self.get_balance_by_query([ + ('cashbook.btype.id', '=', self.dtype.id), + ('cashbook.state', '=', 'open'), + ('date', '<=', IrDate.today()), + ]) + def get_value_currencies(self): """ get balance of bookings in cashbooks by 'currency', converted to currency of evaluation """ - pool = Pool() - Lines = pool.get('cashbook.line') - Currency = pool.get('currency.currency') - IrDate = pool.get('ir.date') - tab_line = Lines.__table__() - cursor = Transaction().connection.cursor() + IrDate = Pool().get('ir.date') - if (self.evaluation is None) or (self.currency is None) or \ - (self.eval_currency is None) or (self.currency_digits is None): + if self.currency is None: return None - total_amount = Decimal('0.0') - with Transaction().set_context({ - '_check_access': True, - }): - lines = Lines.search([ + return self.get_balance_by_query([ ('cashbook.currency.id', '=', self.currency.id), ('cashbook.state', '=', 'open'), ('date', '<=', IrDate.today()), - ], query=True) - - query = lines.join(tab_line, condition=lines.id==tab_line.id, - ).select( - Sum(tab_line.credit - tab_line.debit).as_('balance'), - ) - cursor.execute(*query) - balances = cursor.fetchall() - - for balance in balances: - (bal1,) = balance - - if bal1 is not None: - total_amount += Currency.compute( - self.currency, - bal1, - self.eval_currency, - ) - exp = Decimal(Decimal(1) / 10 ** self.currency_digits) - return total_amount.quantize(exp) + ]) @fields.depends('eval_dtype', 'eval_currency', 'currency_digits', \ 'cashbook', '_parent_cashbook.currency', '_parent_cashbook.balance',\ + 'category', '_parent_category.id', 'evaluation', '_parent_evaluation.id', 'dtype', 'currency') def on_change_with_balance(self, name=None): """ balance of cashbook """ - if self.eval_dtype: - return getattr(self, 'get_value_%s' % self.eval_dtype)() + if (self.evaluation is None) or (self.eval_currency is None) or \ + (self.currency_digits is None) or (self.eval_dtype is None): + return None + return getattr(self, 'get_value_%s' % self.eval_dtype)() # end EvaluationLine diff --git a/locale/de.po b/locale/de.po index f01597e..b770a6f 100644 --- a/locale/de.po +++ b/locale/de.po @@ -134,6 +134,10 @@ msgctxt "selection:cashbook_report.evaluation,dtype:" msgid "Currencys" msgstr "Währungen" +msgctxt "selection:cashbook_report.evaluation,dtype:" +msgid "Categories" +msgstr "Kategorien" + msgctxt "help:cashbook_report.evaluation,dtype:" msgid "Type of data displayed" msgstr "Art der dargestellten Daten" @@ -226,6 +230,10 @@ msgctxt "field:cashbook_report.evaluation,currencies:" msgid "Currencies" msgstr "Währungen" +msgctxt "field:cashbook_report.evaluation,categories:" +msgid "Categories" +msgstr "Kategorien" + msgctxt "field:cashbook_report.evaluation,line_values:" msgid "Line Values" msgstr "Zeilenwerte" diff --git a/locale/en.po b/locale/en.po index 6af9624..67ddf0f 100644 --- a/locale/en.po +++ b/locale/en.po @@ -114,6 +114,10 @@ msgctxt "selection:cashbook_report.evaluation,dtype:" msgid "Currencys" msgstr "Currencys" +msgctxt "selection:cashbook_report.evaluation,dtype:" +msgid "Categories" +msgstr "Categories" + msgctxt "help:cashbook_report.evaluation,dtype:" msgid "Type of data displayed" msgstr "Type of data displayed" @@ -206,6 +210,10 @@ msgctxt "field:cashbook_report.evaluation,currencies:" msgid "Currencies" msgstr "Currencies" +msgctxt "field:cashbook_report.evaluation,categories:" +msgid "Categories" +msgstr "Categories" + msgctxt "field:cashbook_report.evaluation,line_values:" msgid "Line Values" msgstr "Line Values" diff --git a/tests/test_report.py b/tests/test_report.py index a52c979..7d8f2d4 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -230,6 +230,15 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(books_owner1[1].name, 'Book 2') self.assertEqual(books_owner1[1].balance, Decimal('12.5')) + # add category to cashbook + Cashbook.write(*[ + [books_owner1[0]], + { + 'categories': [('create', [{ + 'name': 'Book 1, User 1' + }])], + }]) + evaluation1, = Evaluation.create([{ 'name': 'Evaluation User 1 - Cashbooks', 'dtype': 'cashbooks', @@ -269,7 +278,18 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(evaluation3.line_values[1].name, 'usd') self.assertEqual(evaluation3.line_values[1].balance, Decimal('35.71')) - self.assertEqual(Evaluation.search_count([]), 3) + evaluation4, = Evaluation.create([{ + 'name': 'Evaluation User 1 - Categories', + 'dtype': 'categories', + 'categories': [('add', [x.id for x in books_owner1[0].categories])], + }]) + self.assertEqual(len(evaluation4.categories), 1) + self.assertEqual(evaluation4.currency.rec_name, 'Euro') + self.assertEqual(len(evaluation4.line_values), 1) + self.assertEqual(evaluation4.line_values[0].name, 'Book 1, User 1') + self.assertEqual(evaluation4.line_values[0].balance, Decimal('23.81')) + + self.assertEqual(Evaluation.search_count([]), 4) with Transaction().set_user(users[1].id): with Transaction().set_context({ @@ -280,6 +300,15 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(len(books_owner2), 1) self.assertEqual(books_owner2[0].name, 'Book 3') + # add category to cashbook + Cashbook.write(*[ + [books_owner2[0]], + { + 'categories': [('create', [{ + 'name': 'Book 3, User 2' + }])], + }]) + evaluation1, = Evaluation.create([{ 'name': 'Evaluation User 2 - Cashbooks', 'dtype': 'cashbooks', @@ -317,12 +346,23 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(evaluation3.line_values[1].name, 'usd') self.assertEqual(evaluation3.line_values[1].balance, Decimal('0.0')) - self.assertEqual(Evaluation.search_count([]), 3) + evaluation4, = Evaluation.create([{ + 'name': 'Evaluation User 2 - Categories', + 'dtype': 'categories', + 'categories': [('add', [x.id for x in books_owner2[0].categories])], + }]) + self.assertEqual(len(evaluation4.categories), 1) + self.assertEqual(evaluation4.currency.rec_name, 'Euro') + self.assertEqual(len(evaluation4.line_values), 1) + self.assertEqual(evaluation4.line_values[0].name, 'Book 3, User 2') + self.assertEqual(evaluation4.line_values[0].balance, Decimal('23.0')) + + self.assertEqual(Evaluation.search_count([]), 4) # outside of context - # we should have access to all 6 evaluations + # we should have access to all 8 evaluations evaluations = Evaluation.search([], order=[('name', 'ASC')]) - self.assertEqual(len(evaluations), 6) + self.assertEqual(len(evaluations), 8) self.assertEqual(evaluations[0].name, 'Evaluation User 1 - Cashbooks') self.assertEqual(len(evaluations[0].cashbooks), 2) @@ -333,48 +373,62 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(evaluations[0].line_values[1].name, 'Book 2 | 12.50 usd | Open') self.assertEqual(evaluations[0].line_values[1].balance, Decimal('11.9')) - self.assertEqual(evaluations[1].name, 'Evaluation User 1 - Currencies') - self.assertEqual(len(evaluations[1].currencies), 2) + self.assertEqual(evaluations[1].name, 'Evaluation User 1 - Categories') + self.assertEqual(len(evaluations[1].categories), 1) self.assertEqual(evaluations[1].currency.rec_name, 'Euro') - self.assertEqual(len(evaluations[1].line_values), 2) - self.assertEqual(evaluations[1].line_values[0].name, 'Euro') - self.assertEqual(evaluations[1].line_values[0].balance, Decimal('23.0')) - self.assertEqual(evaluations[1].line_values[1].name, 'usd') - self.assertEqual(evaluations[1].line_values[1].balance, Decimal('35.71')) + self.assertEqual(len(evaluations[1].line_values), 1) + self.assertEqual(evaluations[1].line_values[0].name, 'Book 1, User 1') + self.assertEqual(evaluations[1].line_values[0].balance, Decimal('23.81')) - self.assertEqual(evaluations[2].name, 'Evaluation User 1 - Types') - self.assertEqual(len(evaluations[2].types), 2) + self.assertEqual(evaluations[2].name, 'Evaluation User 1 - Currencies') + self.assertEqual(len(evaluations[2].currencies), 2) self.assertEqual(evaluations[2].currency.rec_name, 'Euro') self.assertEqual(len(evaluations[2].line_values), 2) - self.assertEqual(evaluations[2].line_values[0].name, 'BK - Bank') + self.assertEqual(evaluations[2].line_values[0].name, 'Euro') self.assertEqual(evaluations[2].line_values[0].balance, Decimal('23.0')) - self.assertEqual(evaluations[2].line_values[1].name, 'CAS - Cash') + self.assertEqual(evaluations[2].line_values[1].name, 'usd') self.assertEqual(evaluations[2].line_values[1].balance, Decimal('35.71')) - self.assertEqual(evaluations[3].name, 'Evaluation User 2 - Cashbooks') - self.assertEqual(len(evaluations[3].cashbooks), 1) + self.assertEqual(evaluations[3].name, 'Evaluation User 1 - Types') + self.assertEqual(len(evaluations[3].types), 2) self.assertEqual(evaluations[3].currency.rec_name, 'Euro') - self.assertEqual(len(evaluations[3].line_values), 1) - self.assertEqual(evaluations[3].line_values[0].name, 'Book 3 | 23.00 € | Open') + self.assertEqual(len(evaluations[3].line_values), 2) + self.assertEqual(evaluations[3].line_values[0].name, 'BK - Bank') self.assertEqual(evaluations[3].line_values[0].balance, Decimal('23.0')) + self.assertEqual(evaluations[3].line_values[1].name, 'CAS - Cash') + self.assertEqual(evaluations[3].line_values[1].balance, Decimal('35.71')) - self.assertEqual(evaluations[4].name, 'Evaluation User 2 - Currencies') - self.assertEqual(len(evaluations[4].currencies), 2) + self.assertEqual(evaluations[4].name, 'Evaluation User 2 - Cashbooks') + self.assertEqual(len(evaluations[4].cashbooks), 1) self.assertEqual(evaluations[4].currency.rec_name, 'Euro') - self.assertEqual(len(evaluations[4].line_values), 2) - self.assertEqual(evaluations[4].line_values[0].name, 'Euro') + self.assertEqual(len(evaluations[4].line_values), 1) + self.assertEqual(evaluations[4].line_values[0].name, 'Book 3 | 23.00 € | Open') self.assertEqual(evaluations[4].line_values[0].balance, Decimal('23.0')) - self.assertEqual(evaluations[4].line_values[1].name, 'usd') - self.assertEqual(evaluations[4].line_values[1].balance, Decimal('35.71')) - self.assertEqual(evaluations[5].name, 'Evaluation User 2 - Types') - self.assertEqual(len(evaluations[5].types), 2) + self.assertEqual(evaluations[5].name, 'Evaluation User 2 - Categories') + self.assertEqual(len(evaluations[5].categories), 1) self.assertEqual(evaluations[5].currency.rec_name, 'Euro') - self.assertEqual(len(evaluations[5].line_values), 2) - self.assertEqual(evaluations[5].line_values[0].name, 'BK - Bank') + self.assertEqual(len(evaluations[5].line_values), 1) + self.assertEqual(evaluations[5].line_values[0].name, 'Book 3, User 2') self.assertEqual(evaluations[5].line_values[0].balance, Decimal('23.0')) - self.assertEqual(evaluations[5].line_values[1].name, 'CAS - Cash') - self.assertEqual(evaluations[5].line_values[1].balance, Decimal('35.71')) + + self.assertEqual(evaluations[6].name, 'Evaluation User 2 - Currencies') + self.assertEqual(len(evaluations[6].currencies), 2) + self.assertEqual(evaluations[6].currency.rec_name, 'Euro') + self.assertEqual(len(evaluations[6].line_values), 2) + self.assertEqual(evaluations[6].line_values[0].name, 'Euro') + self.assertEqual(evaluations[6].line_values[0].balance, Decimal('23.0')) + self.assertEqual(evaluations[6].line_values[1].name, 'usd') + self.assertEqual(evaluations[6].line_values[1].balance, Decimal('35.71')) + + self.assertEqual(evaluations[7].name, 'Evaluation User 2 - Types') + self.assertEqual(len(evaluations[7].types), 2) + self.assertEqual(evaluations[7].currency.rec_name, 'Euro') + self.assertEqual(len(evaluations[7].line_values), 2) + self.assertEqual(evaluations[7].line_values[0].name, 'BK - Bank') + self.assertEqual(evaluations[7].line_values[0].balance, Decimal('23.0')) + self.assertEqual(evaluations[7].line_values[1].name, 'CAS - Cash') + self.assertEqual(evaluations[7].line_values[1].balance, Decimal('35.71')) @with_transaction() def test_report_update_name_of_line(self): @@ -428,6 +482,7 @@ class ReportTestCase(CashbookTestCase): Evaluation = pool.get('cashbook_report.evaluation') Types = pool.get('cashbook.type') Currency = pool.get('currency.currency') + Category = pool.get('cashbook.bookcategory') books = self.prep_report_3books() @@ -435,6 +490,15 @@ class ReportTestCase(CashbookTestCase): with Transaction().set_context({ 'company': company.id, }): + + categories = Category.create([{ + 'name': 'Cat 1', + }, { + 'name': 'Cat 2', + }, { + 'name': 'Cat 3', + }]) + # valid evaluation, = Evaluation.create([{ 'name': 'Evaluation 1', @@ -444,6 +508,7 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(len(evaluation.cashbooks), 3) self.assertEqual(len(evaluation.types), 0) self.assertEqual(len(evaluation.currencies), 0) + self.assertEqual(len(evaluation.categories), 0) Evaluation.write(*[ [evaluation], @@ -454,6 +519,7 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(len(evaluation.cashbooks), 0) self.assertEqual(len(evaluation.types), 2) self.assertEqual(len(evaluation.currencies), 0) + self.assertEqual(len(evaluation.categories), 0) # write same dtype again - no change Evaluation.write(*[ @@ -464,6 +530,7 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(len(evaluation.cashbooks), 0) self.assertEqual(len(evaluation.types), 2) self.assertEqual(len(evaluation.currencies), 0) + self.assertEqual(len(evaluation.categories), 0) Evaluation.write(*[ [evaluation], @@ -474,6 +541,18 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(len(evaluation.cashbooks), 0) self.assertEqual(len(evaluation.types), 0) self.assertEqual(len(evaluation.currencies), 2) + self.assertEqual(len(evaluation.categories), 0) + + Evaluation.write(*[ + [evaluation], + { + 'dtype': 'categories', + 'categories': [('add', [x.id for x in Category.search([])])], + }]) + self.assertEqual(len(evaluation.cashbooks), 0) + self.assertEqual(len(evaluation.types), 0) + self.assertEqual(len(evaluation.currencies), 0) + self.assertEqual(len(evaluation.categories), 3) Evaluation.write(*[ [evaluation], @@ -483,6 +562,7 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(len(evaluation.cashbooks), 0) self.assertEqual(len(evaluation.types), 0) self.assertEqual(len(evaluation.currencies), 0) + self.assertEqual(len(evaluation.categories), 0) @with_transaction() def test_report_dtype_validation(self): diff --git a/tryton.cfg b/tryton.cfg index b69f99f..22b19dd 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -3,6 +3,7 @@ version=6.0.0 depends: res cashbook + cashbook_bookcategory extras_depend: dashboard xml: diff --git a/versiondep.txt b/versiondep.txt index dd7b3c7..4605d4c 100644 --- a/versiondep.txt +++ b/versiondep.txt @@ -1 +1,2 @@ cashbook;6.0.19;6.0.999;mds +cashbook_bookcategory;6.0.2;6.0.999;mds diff --git a/view/evaluation_form.xml b/view/evaluation_form.xml index 0e890fe..236f65c 100644 --- a/view/evaluation_form.xml +++ b/view/evaluation_form.xml @@ -25,4 +25,5 @@ full copyright notices and license terms. --> +