diff --git a/__init__.py b/__init__.py index 92ebf35..e4f23b7 100644 --- a/__init__.py +++ b/__init__.py @@ -4,7 +4,8 @@ # full copyright notices and license terms. from trytond.pool import Pool -from .evaluation import Evaluation, EvaluationLineRel +from .evaluation import Evaluation +from .line import EvaluationLine from .currency import Currency from .evaluation_context import EvaluationContext from .evaluation_wizard import OpenChartWizard @@ -13,7 +14,7 @@ def register(): Pool.register( Currency, Evaluation, - EvaluationLineRel, + EvaluationLine, EvaluationContext, module='cashbook_report', type_='model') Pool.register( diff --git a/evaluation.py b/evaluation.py index 20a12e6..4408491 100644 --- a/evaluation.py +++ b/evaluation.py @@ -3,13 +3,9 @@ # The COPYRIGHT file at the top level of this repository contains the # full copyright notices and license terms. -from decimal import Decimal -from sql.aggregate import Sum -from trytond.model import ModelView, ModelSQL, fields, Check -from trytond.pyson import Eval, Or, Bool, Id, Len +from trytond.model import ModelView, ModelSQL, fields +from trytond.pyson import Eval from trytond.transaction import Transaction -from trytond.i18n import gettext -from trytond.exceptions import UserError from trytond.pool import Pool from .colors import sel_color as sel_bgcolor from .templates import template_view_graph, template_view_line @@ -172,15 +168,11 @@ class Evaluation(ModelSQL, ModelView): for evaluation in evaluations: if evaluation.dtype: # skip if no data to show - if len(getattr(evaluation, evaluation.dtype, [])) == 0: + if len(evaluation.line_values) == 0: continue view_graph, = UiView.create([{ - 'model': 'cashbook_report.%s' % { - 'cashbooks': 'eval_book', - 'types': 'eval_type', - 'currencies': 'eval_currency', - }[evaluation.dtype], + 'model': 'cashbook_report.eval_line', 'module': 'cashbook_report', 'priority': 10, 'type': 'graph', @@ -220,15 +212,16 @@ class Evaluation(ModelSQL, ModelView): """ unlink records if dtype changes """ to_write = [] - actions = iter(args) to_update_uiview = [] - for evaluations, values in zip(actions, actions): + actions = iter(args) + for evaluations, values in zip(actions, actions): # update ui-view if related fields change if len(set({'name', 'dtype', 'bgcolor', 'maincolor', 'legend', 'chart'}).intersection(values.keys())) > 0: to_update_uiview.extend(evaluations) + # unlink records if dtype changes if 'dtype' in values.keys(): for evaluation in evaluations: if evaluation.dtype == values['dtype']: @@ -278,235 +271,3 @@ class Evaluation(ModelSQL, ModelView): # end Evaluation - -class EvaluationLineRel(ModelSQL): - 'Evaluation Line Relation' - __name__ = 'cashbook_report.eval_line' - - evaluation = fields.Many2One(string='Evaluation', required=True, - select=True, ondelete='CASCADE', - model_name='cashbook_report.evaluation') - cashbook = fields.Many2One(string='Cashbook', select=True, ondelete='CASCADE', - model_name='cashbook.book', - states={ - 'required': Eval('eval_dtype', '') == 'cashbooks', - }, depends=['eval_dtype']) - dtype = fields.Many2One(string='Type', select=True, ondelete='CASCADE', - model_name='cashbook.type', - states={ - 'required': Eval('eval_dtype', '') == 'types', - }, depends=['eval_dtype']) - currency = fields.Many2One(string='Currency', select=True, ondelete='CASCADE', - model_name='currency.currency', - states={ - 'required': Eval('eval_dtype', '') == 'currencies', - }, depends=['eval_dtype']) - - # currency of evaluation - eval_currency = fields.Function(fields.Many2One(model_name='currency.currency', - string="Currency", readonly=True), 'on_change_with_eval_currency') - currency_digits = fields.Function(fields.Integer(string='Currency Digits', - readonly=True), 'on_change_with_currency_digits') - eval_dtype = fields.Function(fields.Char(string='Data type', readonly=True), - 'on_change_with_eval_dtype') - - name = fields.Function(fields.Char(string='Name', readonly=True), - 'on_change_with_name') - balance = fields.Function(fields.Numeric(string='Balance', - readonly=True, digits=(16, Eval('currency_digits', 2)), - depends=['currency_digits']), - 'on_change_with_balance') - - @classmethod - def fields_view_get(cls, view_id, view_type='form'): - """ replace form-view-id - """ - pool = Pool() - ModelData = pool.get('ir.model.data') - Evaluation = pool.get('cashbook_report.evaluation') - context = Transaction().context - - # get id of origin chart-form - form_id = ModelData.get_id('cashbook_report', 'point_view_graph') - - # active_chart was added by tree_open-action - active_evaluation = context.get('active_evaluation', None) - - # check if we are requested for our default form... - if (view_type == 'graph') and (view_id == form_id) and \ - (active_evaluation is not None): - evaluation, = Evaluation.browse([active_evaluation]) - if evaluation.ui_view_point: - # ... switch to view, created by evaluation-config - view_id = evaluation.ui_view_point.id - - return super(EvaluationLineRel, cls).fields_view_get( - view_id=view_id, view_type=view_type) - - @fields.depends('evaluation', '_parent_evaluation.dtype') - def on_change_with_eval_dtype(self, name=None): - """ get dtape from parent - """ - if self.evaluation: - return self.evaluation.dtype - - @fields.depends('evaluation', '_parent_evaluation.currency') - def on_change_with_eval_currency(self, name=None): - """ currency of evaluation - """ - if self.evaluation: - return self.evaluation.currency.id - - @fields.depends('evaluation', '_parent_evaluation.currency') - def on_change_with_currency_digits(self, name=None): - """ currency-digits of evaluation - """ - if self.evaluation: - return self.evaluation.currency.digits - else: - return 2 - - @classmethod - def validate(cls, records): - """ check parent record - """ - super(EvaluationLineRel, cls).validate(records) - for record in records: - if (record.evaluation.dtype != 'cashbooks') and \ - (record.cashbook is not None): - raise UserError(gettext( - 'cashbook_report.msg_invalid_dtype', - typename = gettext('cashbook_report.msg_dtype_cashbook'), - )) - if (record.evaluation.dtype != 'types') and \ - (record.dtype is not None): - raise UserError(gettext( - 'cashbook_report.msg_invalid_dtype', - typename = gettext('cashbook_report.msg_dtype_type'), - )) - if (record.evaluation.dtype != 'currencies') and \ - (record.currency is not None): - raise UserError(gettext( - 'cashbook_report.msg_invalid_dtype', - typename = gettext('cashbook_report.msg_dtype_currency'), - )) - - @fields.depends('eval_dtype', 'cashbook', 'dtype', 'currency') - def on_change_with_name(self, name=None): - """ get name of Type - """ - if self.eval_dtype: - return getattr( - getattr(self, { - 'cashbooks': 'cashbook', - 'types': 'dtype', - 'currencies': 'currency', - }[self.eval_dtype], None), - 'rec_name', None) - - 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 - """ - pool = Pool() - Lines = pool.get('cashbook.line') - Cashbook = pool.get('cashbook.book') - Currency = pool.get('currency.currency') - 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 - - lines = Lines.search([ - ('cashbook.btype.id', '=', self.dtype.id), - ('cashbook.state', '=', 'open'), - ('cashbook.owner.id', '=', Transaction().user), - ], query=True) - - query = lines.join(tab_line, condition=lines.id==tab_line.id, - ).join(tab_book, condition=tab_book.id==tab_line.cashbook, - ).select( - tab_book.currency, - Sum(tab_line.credit - tab_line.debit).as_('balance'), - group_by=[tab_book.currency], - ) - cursor.execute(*query) - balances = cursor.fetchall() - - total_amount = Decimal('0.0') - for balance in balances: - (id_currency, bal1) = balance - - total_amount += Currency.compute( - Currency(id_currency), - bal1, - self.eval_currency, - ) - exp = Decimal(Decimal(1) / 10 ** self.currency_digits) - return total_amount.quantize(exp) - - 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') - tab_line = Lines.__table__() - cursor = Transaction().connection.cursor() - - if (self.evaluation is None) or (self.currency is None) or \ - (self.eval_currency is None) or (self.currency_digits is None): - return None - - lines = Lines.search([ - ('cashbook.currency.id', '=', self.currency.id), - ('cashbook.state', '=', 'open'), - ('cashbook.owner.id', '=', Transaction().user), - ], 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() - - total_amount = Decimal('0.0') - for balance in balances: - (bal1,) = balance - - 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',\ - 'evaluation', '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)() - -# end EvaluationLineRel diff --git a/evaluation_context.py b/evaluation_context.py index 5aa0b4a..fa1e3f3 100644 --- a/evaluation_context.py +++ b/evaluation_context.py @@ -12,8 +12,7 @@ class EvaluationContext(ModelView): __name__ = 'cashbook_report.evaluation.context' evaluation = fields.Many2One(string='Evaluation', readonly=True, - model_name='cashbook_report.evaluation', - states={'invisible': True}) + model_name='cashbook_report.evaluation') @classmethod def default_evaluation(cls): diff --git a/evaluation_context.xml b/evaluation_context.xml index 2045f40..0b72704 100644 --- a/evaluation_context.xml +++ b/evaluation_context.xml @@ -23,7 +23,7 @@ full copyright notices and license terms. --> - + diff --git a/graph.xml b/graph.xml deleted file mode 100644 index 23c6516..0000000 --- a/graph.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - cashbook.book - graph - - book_graph - - - - diff --git a/ir.xml b/ir.xml new file mode 100644 index 0000000..0a7916a --- /dev/null +++ b/ir.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + Anon: IR UI View read + + + + + + + + + + + + + + + + Owner: IR UI View edit + + + + + + + + + + + + + + + + + + + + Administrator: IR UI View edit + + + + + + + + + + + + + + + + + + diff --git a/line.py b/line.py new file mode 100644 index 0000000..5924a31 --- /dev/null +++ b/line.py @@ -0,0 +1,246 @@ +# -*- coding: utf-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. + +from decimal import Decimal +from sql.aggregate import Sum +from trytond.model import ModelView, ModelSQL, fields +from trytond.pyson import Eval +from trytond.transaction import Transaction +from trytond.i18n import gettext +from trytond.exceptions import UserError +from trytond.pool import Pool + + +class EvaluationLine(ModelSQL, ModelView): + 'Evaluation Line Relation' + __name__ = 'cashbook_report.eval_line' + + evaluation = fields.Many2One(string='Evaluation', required=True, + select=True, ondelete='CASCADE', + model_name='cashbook_report.evaluation') + cashbook = fields.Many2One(string='Cashbook', select=True, ondelete='CASCADE', + model_name='cashbook.book', + states={ + 'required': Eval('eval_dtype', '') == 'cashbooks', + }, depends=['eval_dtype']) + dtype = fields.Many2One(string='Type', select=True, ondelete='CASCADE', + model_name='cashbook.type', + states={ + 'required': Eval('eval_dtype', '') == 'types', + }, depends=['eval_dtype']) + currency = fields.Many2One(string='Currency', select=True, ondelete='CASCADE', + model_name='currency.currency', + states={ + 'required': Eval('eval_dtype', '') == 'currencies', + }, depends=['eval_dtype']) + + # dtype + currency of evaluation + eval_dtype = fields.Function(fields.Char(string='Data type', readonly=True), + 'on_change_with_eval_dtype') + eval_currency = fields.Function(fields.Many2One(model_name='currency.currency', + string="Currency", readonly=True), 'on_change_with_eval_currency') + currency_digits = fields.Function(fields.Integer(string='Currency Digits', + readonly=True), 'on_change_with_currency_digits') + + name = fields.Function(fields.Char(string='Name', readonly=True), + 'on_change_with_name') + balance = fields.Function(fields.Numeric(string='Balance', + readonly=True, digits=(16, Eval('currency_digits', 2)), + depends=['currency_digits']), + 'on_change_with_balance') + + @classmethod + def fields_view_get(cls, view_id, view_type='form'): + """ replace form-view-id + """ + pool = Pool() + ModelData = pool.get('ir.model.data') + Evaluation = pool.get('cashbook_report.evaluation') + context = Transaction().context + + # get id of origin chart-form + form_id = ModelData.get_id('cashbook_report', 'evalline_view_graph') + + # active_chart was added by tree_open-action + active_evaluation = context.get('active_evaluation', None) + + # check if we are requested for our default form... + if (view_type == 'graph') and (view_id == form_id) and \ + (active_evaluation is not None): + evaluation, = Evaluation.browse([active_evaluation]) + if evaluation.ui_view_chart: + # ... switch to view, created by evaluation-config + view_id = evaluation.ui_view_chart.id + + return super(EvaluationLine, cls).fields_view_get( + view_id=view_id, view_type=view_type) + + @fields.depends('evaluation', '_parent_evaluation.dtype') + def on_change_with_eval_dtype(self, name=None): + """ get dtape from parent + """ + if self.evaluation: + return self.evaluation.dtype + + @fields.depends('evaluation', '_parent_evaluation.currency') + def on_change_with_eval_currency(self, name=None): + """ currency of evaluation + """ + if self.evaluation: + return self.evaluation.currency.id + + @fields.depends('evaluation', '_parent_evaluation.currency') + def on_change_with_currency_digits(self, name=None): + """ currency-digits of evaluation + """ + if self.evaluation: + return self.evaluation.currency.digits + else: + return 2 + + @classmethod + def validate(cls, records): + """ check parent record + """ + super(EvaluationLine, cls).validate(records) + for record in records: + if (record.evaluation.dtype != 'cashbooks') and \ + (record.cashbook is not None): + raise UserError(gettext( + 'cashbook_report.msg_invalid_dtype', + typename = gettext('cashbook_report.msg_dtype_cashbook'), + )) + if (record.evaluation.dtype != 'types') and \ + (record.dtype is not None): + raise UserError(gettext( + 'cashbook_report.msg_invalid_dtype', + typename = gettext('cashbook_report.msg_dtype_type'), + )) + if (record.evaluation.dtype != 'currencies') and \ + (record.currency is not None): + raise UserError(gettext( + 'cashbook_report.msg_invalid_dtype', + typename = gettext('cashbook_report.msg_dtype_currency'), + )) + + @fields.depends('eval_dtype', 'cashbook', 'dtype', 'currency') + def on_change_with_name(self, name=None): + """ get name of Type + """ + if self.eval_dtype: + return getattr( + getattr(self, { + 'cashbooks': 'cashbook', + 'types': 'dtype', + 'currencies': 'currency', + }[self.eval_dtype], None), + 'rec_name', None) + + 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 + """ + pool = Pool() + Lines = pool.get('cashbook.line') + Cashbook = pool.get('cashbook.book') + Currency = pool.get('currency.currency') + 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 + + lines = Lines.search([ + ('cashbook.btype.id', '=', self.dtype.id), + ('cashbook.state', '=', 'open'), + ('cashbook.owner.id', '=', Transaction().user), + ], query=True) + + query = lines.join(tab_line, condition=lines.id==tab_line.id, + ).join(tab_book, condition=tab_book.id==tab_line.cashbook, + ).select( + tab_book.currency, + Sum(tab_line.credit - tab_line.debit).as_('balance'), + group_by=[tab_book.currency], + ) + cursor.execute(*query) + balances = cursor.fetchall() + + total_amount = Decimal('0.0') + for balance in balances: + (id_currency, bal1) = balance + + total_amount += Currency.compute( + Currency(id_currency), + bal1, + self.eval_currency, + ) + exp = Decimal(Decimal(1) / 10 ** self.currency_digits) + return total_amount.quantize(exp) + + 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') + tab_line = Lines.__table__() + cursor = Transaction().connection.cursor() + + if (self.evaluation is None) or (self.currency is None) or \ + (self.eval_currency is None) or (self.currency_digits is None): + return None + + lines = Lines.search([ + ('cashbook.currency.id', '=', self.currency.id), + ('cashbook.state', '=', 'open'), + ('cashbook.owner.id', '=', Transaction().user), + ], 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() + + total_amount = Decimal('0.0') + for balance in balances: + (bal1,) = balance + + 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',\ + '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)() + +# end EvaluationLine diff --git a/line_value.xml b/line.xml similarity index 100% rename from line_value.xml rename to line.xml diff --git a/tests/test_report.py b/tests/test_report.py index 682d048..845e344 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -307,7 +307,7 @@ class ReportTestCase(CashbookTestCase): self.assertEqual(evaluation.currency.code, 'EUR') # check uiview - self.assertEqual(evaluation.ui_view_chart.model, 'cashbook_report.eval_book') + self.assertEqual(evaluation.ui_view_chart.model, 'cashbook_report.eval_line') self.assertEqual(evaluation.ui_view_chart.module, 'cashbook_report') self.assertEqual(evaluation.ui_view_chart.priority, 10) self.assertEqual(evaluation.ui_view_chart.type, 'graph') diff --git a/tryton.cfg b/tryton.cfg index 6709e99..90013f0 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -1,13 +1,14 @@ [tryton] version=6.0.0 depends: + ir cashbook xml: icon.xml message.xml - graph.xml + ir.xml evaluation.xml - line_value.xml + line.xml evaluation_context.xml evaluation_wizard.xml menu.xml diff --git a/view/book_graph.xml b/view/evalline_graph.xml similarity index 100% rename from view/book_graph.xml rename to view/evalline_graph.xml diff --git a/view/evalline_list.xml b/view/evalline_list.xml new file mode 100644 index 0000000..15d6ae2 --- /dev/null +++ b/view/evalline_list.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/view/evaluation_form.xml b/view/evaluation_form.xml index ab681d7..3fac704 100644 --- a/view/evaluation_form.xml +++ b/view/evaluation_form.xml @@ -2,31 +2,23 @@ -
- - - - - - - - + + +