Compare commits

...

20 commits

Author SHA1 Message Date
Frederik Jaeckel
991db732bc Version 6.0.6 2023-02-06 20:23:59 +01:00
Frederik Jaeckel
b847d64187 add profit/loss-values for selection of cashbooks by btype 2023-02-06 20:22:07 +01:00
Frederik Jaeckel
a71f05b1da Etikett ver 6.0.5 zum Änderungssatz b2625d3504ac hinzugefügt 2023-02-06 09:33:33 +01:00
Frederik Jaeckel
081be8392b Version 6.0.5 2023-02-06 09:33:24 +01:00
Frederik Jaeckel
4ab46071a3 fix: evaluation cashbook-currentvalue/diff return 'balance' on non-asset-cashbooks 2023-02-06 09:32:01 +01:00
Frederik Jaeckel
3c4f2ea47b Etikett ver 6.0.4 zum Änderungssatz 61085fa941bc hinzugefügt 2023-02-05 18:20:44 +01:00
Frederik Jaeckel
8db7bcf376 Version 6.0.4 2023-02-05 18:20:36 +01:00
Frederik Jaeckel
e3a41b821b convert results to evaluation-currency, fix states 2023-02-05 18:16:49 +01:00
Frederik Jaeckel
0c3a130ef5 evaluation: extend categories-diff/percent/value + tests 2023-02-05 14:39:00 +01:00
Frederik Jaeckel
9774f183ad extend evaluation for cashbook-profit/loss amount/percent/diff - todo 2023-02-02 23:35:58 +01:00
Frederik Jaeckel
6ee40e8cff Etikett ver 6.0.3 zum Änderungssatz b738f8a6caa2 hinzugefügt 2022-11-08 22:03:34 +01:00
Frederik Jaeckel
d5bc461cd6 Version 6.0.3 2022-11-08 22:03:24 +01:00
Frederik Jaeckel
b6c30a10df Kassenbuchkategorie eingebunden + Test 2022-11-08 21:56:03 +01:00
Frederik Jaeckel
d774fa2e20 line: beachtet nur buchungen bis zum aktuellen tag 2022-11-07 08:57:39 +01:00
Frederik Jaeckel
f06eacbadc auswertung: dashboard-window aktualisieren bei änderung der auswertung 2022-11-06 15:40:23 +01:00
Frederik Jaeckel
c0432d609d Etikett ver 6.0.2 zum Änderungssatz 03b7ae6ac62e hinzugefügt 2022-11-05 21:55:48 +01:00
Frederik Jaeckel
1009d0077e Version 6.0.2 2022-11-05 21:55:36 +01:00
Frederik Jaeckel
81c1624d97 auswertung: sequence-sortierung,
line: zugriff auf buchungen nur noch per berechtigungen
2022-11-05 21:43:28 +01:00
Frederik Jaeckel
80fbb5d722 Etikett ver 6.0.1 zum Änderungssatz 1c6bf7847073 hinzugefügt 2022-11-05 13:57:38 +01:00
Frederik Jaeckel
ceaeb67cd7 Version 6.0.1 2022-11-05 13:57:29 +01:00
15 changed files with 988 additions and 152 deletions

View file

@ -14,6 +14,33 @@ Requires
Changes Changes
======= =======
*6.0.6 - 06.02.2023*
- add: profit/loss-values for btype-selection of cashbooks
*6.0.5 - 06.02.2023*
- fix: values on non-asset-cashbooks
*6.0.4 - 05.02.2023*
- add: investment to evaluation-types
*6.0.3 - 08.11.2022*
- add: cashbook-categories for evaluation
- updt: optimized update of evaluation with existing dashboard-actions
- updt: limit bookings in evaluation-result to today
*6.0.2 - 05.11.2022*
- evaluation-line: permissions optimized
- evaluation: sorting by sequence
*6.0.1 - 05.11.2022*
- works
*6.0.0 - 28.10.2022* *6.0.0 - 28.10.2022*
- init - init

View file

@ -9,6 +9,8 @@ from .line import EvaluationLine
from .currency import Currency from .currency import Currency
from .evaluation_context import EvaluationContext from .evaluation_context import EvaluationContext
from .evaluation_wizard import OpenChartWizard from .evaluation_wizard import OpenChartWizard
from .investment import InvestmentEvaluation, InvestmentLine
def register(): def register():
Pool.register( Pool.register(
@ -20,3 +22,7 @@ def register():
Pool.register( Pool.register(
OpenChartWizard, OpenChartWizard,
module='cashbook_report', type_='wizard') module='cashbook_report', type_='wizard')
Pool.register(
InvestmentEvaluation,
InvestmentLine,
module='cashbook_report', type_='model', depends=['cashbook_investment'])

View file

@ -3,21 +3,16 @@
# The COPYRIGHT file at the top level of this repository contains the # The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms. # full copyright notices and license terms.
from trytond.model import ModelView, ModelSQL, fields from trytond.model import ModelView, ModelSQL, fields, sequence_ordered
from trytond.pyson import Eval from trytond.pyson import Eval
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.pool import Pool from trytond.pool import Pool
from trytond.i18n import gettext
from .colors import sel_color as sel_bgcolor from .colors import sel_color as sel_bgcolor
from .templates import template_view_graph, template_view_line from .templates import template_view_graph, template_view_line, \
cashbook_types, category_types, booktype_types
sel_etype = [
('cashbooks', 'Cashbooks'),
('types', 'Types of Cashbooks'),
('currencies', 'Currencys'),
#('category', 'Category'),
]
sel_chart = [ sel_chart = [
('vbar', 'Vertical Bars'), ('vbar', 'Vertical Bars'),
('hbar', 'Horizontal Bars'), ('hbar', 'Horizontal Bars'),
@ -36,7 +31,7 @@ sel_maincolor = [
] ]
class Evaluation(ModelSQL, ModelView): class Evaluation(sequence_ordered(), ModelSQL, ModelView):
'Evaluation' 'Evaluation'
__name__ = 'cashbook_report.evaluation' __name__ = 'cashbook_report.evaluation'
@ -44,7 +39,7 @@ class Evaluation(ModelSQL, ModelView):
required=True, ondelete="RESTRICT") required=True, ondelete="RESTRICT")
name = fields.Char(string='Name', required=True) name = fields.Char(string='Name', required=True)
dtype = fields.Selection(string='Data type', required=True, dtype = fields.Selection(string='Data type', required=True,
sort=False, selection=sel_etype, sort=True, selection='get_sel_etype',
help='Type of data displayed') help='Type of data displayed')
dtype_string = dtype.translated('dtype') dtype_string = dtype.translated('dtype')
chart = fields.Selection(string='Chart type', required=True, chart = fields.Selection(string='Chart type', required=True,
@ -57,7 +52,6 @@ class Evaluation(ModelSQL, ModelView):
bgcolor = fields.Selection(string='Background Color', required=True, bgcolor = fields.Selection(string='Background Color', required=True,
help='Background color of the chart area.', sort=False, help='Background color of the chart area.', sort=False,
selection=sel_bgcolor) selection=sel_bgcolor)
posted = fields.Boolean(string='Posted', help='Posted amounts only.')
currency = fields.Many2One(string='Currency', ondelete='RESTRICT', currency = fields.Many2One(string='Currency', ondelete='RESTRICT',
model_name='currency.currency') model_name='currency.currency')
@ -65,13 +59,13 @@ class Evaluation(ModelSQL, ModelView):
relation_name='cashbook_report.eval_line', relation_name='cashbook_report.eval_line',
origin='evaluation', target='cashbook', origin='evaluation', target='cashbook',
states={ states={
'invisible': Eval('dtype', '') != 'cashbooks', 'invisible': ~Eval('dtype', '').in_(cashbook_types),
}, depends=['dtype']) }, depends=['dtype'])
types = fields.Many2Many(string='Types', types = fields.Many2Many(string='Types',
relation_name='cashbook_report.eval_line', relation_name='cashbook_report.eval_line',
origin='evaluation', target='dtype', origin='evaluation', target='dtype',
states={ states={
'invisible': Eval('dtype', '') != 'types', 'invisible': ~Eval('dtype', '').in_(booktype_types),
}, depends=['dtype']) }, depends=['dtype'])
currencies = fields.Many2Many(string='Currencies', currencies = fields.Many2Many(string='Currencies',
relation_name='cashbook_report.eval_line', relation_name='cashbook_report.eval_line',
@ -80,6 +74,12 @@ class Evaluation(ModelSQL, ModelView):
states={ states={
'invisible': Eval('dtype', '') != 'currencies', 'invisible': Eval('dtype', '') != 'currencies',
}, depends=['dtype']) }, depends=['dtype'])
categories = fields.Many2Many(string='Categories',
relation_name='cashbook_report.eval_line',
origin='evaluation', target='category',
states={
'invisible': ~Eval('dtype', '').in_(category_types),
}, depends=['dtype'])
line_values = fields.One2Many(string='Line Values', line_values = fields.One2Many(string='Line Values',
field='evaluation', readonly=True, field='evaluation', readonly=True,
@ -108,12 +108,6 @@ class Evaluation(ModelSQL, ModelView):
def default_company(): def default_company():
return Transaction().context.get('company') or None return Transaction().context.get('company') or None
@classmethod
def default_posted(cls):
""" default: False
"""
return False
@classmethod @classmethod
def default_bgcolor(cls): def default_bgcolor(cls):
""" default: Yellow 5 """ default: Yellow 5
@ -144,6 +138,17 @@ class Evaluation(ModelSQL, ModelView):
""" """
return 'pie' return 'pie'
@classmethod
def get_sel_etype(cls):
""" get list of evaluation-types
"""
return [
('cashbooks', gettext('cashbook_report.msg_dtype_cashbook')),
('types', gettext('cashbook_report.msg_dtype_type')),
('currencies', gettext('cashbook_report.msg_dtype_currency')),
('categories', gettext('cashbook_report.msg_dtype_category')),
]
@classmethod @classmethod
def get_create_view_data(cls, evaluation): def get_create_view_data(cls, evaluation):
""" generate dictionary to create view-xml """ generate dictionary to create view-xml
@ -200,10 +205,13 @@ class Evaluation(ModelSQL, ModelView):
ActWin = pool.get('ir.action.act_window') ActWin = pool.get('ir.action.act_window')
ActView = pool.get('ir.action.act_window.view') ActView = pool.get('ir.action.act_window.view')
Evaluation2 = pool.get('cashbook_report.evaluation') Evaluation2 = pool.get('cashbook_report.evaluation')
try :
cls.uiview_delete(evaluations) DashboardAction = pool.get('dashboard.action')
except:
DashboardAction = None
to_write_eval = [] to_write_eval = []
to_write_dbaction = []
for evaluation in evaluations: for evaluation in evaluations:
with Transaction().set_context({ with Transaction().set_context({
'_check_access': False, '_check_access': False,
@ -233,6 +241,24 @@ class Evaluation(ModelSQL, ModelView):
'dashb_actview': dashb_actview.id, 'dashb_actview': dashb_actview.id,
}]) }])
# prepare update dasboard-action
if DashboardAction is not None:
if evaluation.dashb_actwin:
db_actions = DashboardAction.search([
('act_window.id', '=', evaluation.dashb_actwin.id),
])
if len(db_actions) > 0:
to_write_dbaction.extend([
db_actions,
{
'act_window': dashb_actwin.id,
}])
if len(to_write_dbaction) > 0:
DashboardAction.write(*to_write_dbaction)
cls.uiview_delete(evaluations)
if len(to_write_eval) > 0: if len(to_write_eval) > 0:
Evaluation2.write(*to_write_eval) Evaluation2.write(*to_write_eval)
@ -264,33 +290,16 @@ class Evaluation(ModelSQL, ModelView):
if evaluation.dtype == values['dtype']: if evaluation.dtype == values['dtype']:
continue continue
if (values['dtype'] != 'cashbooks') and \ for dt in ['cashbooks', 'types', 'currencies', 'categories']:
(len(evaluation.cashbooks) > 0): if (not values['dtype'].startswith(dt)) and \
to_write.extend([ (len(getattr(evaluation, dt)) > 0):
[evaluation], to_write.extend([
{ [evaluation],
'cashbooks': [ {
('remove', [x.id for x in evaluation.cashbooks]) dt: [
], ('remove', [x.id for x in getattr(evaluation, dt)])
}]) ],
}])
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 = list(args)
args.extend(to_write) args.extend(to_write)
@ -307,4 +316,3 @@ class Evaluation(ModelSQL, ModelView):
super(Evaluation, cls).delete(evaluations) super(Evaluation, cls).delete(evaluations)
# end Evaluation # end Evaluation

203
investment.py Normal file
View file

@ -0,0 +1,203 @@
# -*- 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 trytond.pool import PoolMeta, Pool
from trytond.i18n import gettext
from decimal import Decimal
class InvestmentEvaluation(metaclass=PoolMeta):
__name__ = 'cashbook_report.evaluation'
@classmethod
def get_sel_etype(cls):
""" get list of evaluation-types
"""
result = super(InvestmentEvaluation, cls).get_sel_etype()
result.extend([
('cashbooks_gldiff', gettext('cashbook_report.msg_dtype_cashbook_gldiff')),
('cashbooks_glperc', gettext('cashbook_report.msg_dtype_cashbook_glperc')),
('cashbooks_glvalue', gettext('cashbook_report.msg_dtype_cashbooks_glvalue')),
('category_gldiff', gettext('cashbook_report.msg_dtype_category_gldiff')),
('category_glvalue', gettext('cashbook_report.msg_dtype_category_glvalue')),
('category_glperc', gettext('cashbook_report.msg_dtype_category_glperc')),
('types_gldiff', gettext('cashbook_report.msg_dtype_types_gldiff')),
('types_glvalue', gettext('cashbook_report.msg_dtype_types_glvalue')),
('types_glperc', gettext('cashbook_report.msg_dtype_types_glperc')),
])
return result
# end InvestmentEvaluation
class InvestmentLine(metaclass=PoolMeta):
__name__ = 'cashbook_report.eval_line'
def get_value_types_glperc(self):
""" get percent of profit/loss by type
"""
if self.dtype is None:
return None
return self.get_percent_by_query([
('btype.id', '=', self.dtype.id),
])
def get_value_category_glperc(self):
""" get percent of profit/loss by category
"""
if self.category is None:
return None
return self.get_percent_by_query([
('categories.id', '=', self.category.id),
])
def get_percent_by_query(self, query):
""" get percentual difference of bookings in categories
converted to currency of evaluation
"""
Book = Pool().get('cashbook.book')
query2 = [('state', '=', 'open')]
query2.extend(query)
books = Book.search(query2)
value = Decimal('0.0')
amount = Decimal('0.0')
if len(books) > 0:
value = sum([x.current_value_ref for x in books
if (x.current_value_ref is not None) and (x.feature == 'asset')])
amount = sum([x.balance_ref for x in books
if (x.balance_ref is not None) and (x.feature == 'asset')])
if amount != Decimal('0.0'):
return self.convert_to_evalcurrency(
books[0].company.currency,
Decimal('100.0') * value / amount - Decimal('100.0'),
)
return Decimal('0.0')
def get_value_types_glvalue(self):
""" get current value by type
"""
if self.dtype is None:
return None
return self.get_currentvalue_by_query([
('btype.id', '=', self.dtype.id),
])
def get_value_category_glvalue(self):
""" get current value by category
"""
if self.category is None:
return None
return self.get_currentvalue_by_query([
('categories.id', '=', self.category.id),
])
def get_currentvalue_by_query(self, query):
""" get current value of bookings in categories
converted to currency of evaluation
"""
Book = Pool().get('cashbook.book')
query2 = [('state', '=', 'open')]
query2.extend(query)
books = Book.search(query2)
result = Decimal('0.0')
if len(books) > 0:
for book in books:
if book.feature == 'asset':
if book.current_value_ref is not None:
result += book.current_value_ref
else :
if book.balance_ref is not None:
result += book.balance_ref
return self.convert_to_evalcurrency(
books[0].company.currency, result)
return result
def get_value_types_gldiff(self):
""" get difference amount by type
"""
if self.dtype is None:
return None
return self.get_difference_by_query([
('btype.id', '=', self.dtype.id),
])
def get_value_category_gldiff(self):
""" get difference amount by category
"""
if self.category is None:
return None
return self.get_difference_by_query([
('categories.id', '=', self.category.id),
])
def get_difference_by_query(self, query):
""" get difference amount of bookings in categories
converted to currency of evaluation
"""
Book = Pool().get('cashbook.book')
query2 = [('state', '=', 'open')]
query2.extend(query)
books = Book.search(query2)
result = Decimal('0.0')
if len(books) > 0:
result = sum([x.current_value_ref - x.balance_ref for x in books
if (x.current_value_ref is not None) and \
(x.balance_ref is not None) and \
(x.feature == 'asset')])
result = self.convert_to_evalcurrency(
books[0].company.currency, result)
return result
def get_value_cashbooks_gldiff(self):
""" amount of profit/loss of cashbooks
"""
Currency = Pool().get('currency.currency')
if self.cashbook:
if self.cashbook.feature == 'asset':
return self.convert_to_evalcurrency(
self.cashbook.currency,
self.cashbook.diff_amount)
else :
return Decimal('0.0')
def get_value_cashbooks_glvalue(self):
""" current value of cashbooks
"""
Currency = Pool().get('currency.currency')
if self.cashbook:
if self.cashbook.feature == 'asset':
return self.convert_to_evalcurrency(
self.cashbook.currency,
self.cashbook.current_value)
else :
return self.convert_to_evalcurrency(
self.cashbook.currency,
self.cashbook.balance_ref)
def get_value_cashbooks_glperc(self):
""" percent of profit/loss of cashbooks
"""
if self.cashbook:
if self.cashbook.feature == 'asset':
return self.cashbook.diff_percent
else :
return Decimal('0.0')
# end InvestmentLine

175
line.py
View file

@ -11,6 +11,7 @@ from trytond.transaction import Transaction
from trytond.i18n import gettext from trytond.i18n import gettext
from trytond.exceptions import UserError from trytond.exceptions import UserError
from trytond.pool import Pool from trytond.pool import Pool
from .templates import cashbook_types, category_types, booktype_types
class EvaluationLine(ModelSQL, ModelView): class EvaluationLine(ModelSQL, ModelView):
@ -23,18 +24,23 @@ class EvaluationLine(ModelSQL, ModelView):
cashbook = fields.Many2One(string='Cashbook', select=True, ondelete='CASCADE', cashbook = fields.Many2One(string='Cashbook', select=True, ondelete='CASCADE',
model_name='cashbook.book', model_name='cashbook.book',
states={ states={
'required': Eval('eval_dtype', '') == 'cashbooks', 'required': Eval('eval_dtype', '').in_(cashbook_types),
}, depends=['eval_dtype']) }, depends=['eval_dtype'])
dtype = fields.Many2One(string='Type', select=True, ondelete='CASCADE', dtype = fields.Many2One(string='Type', select=True, ondelete='CASCADE',
model_name='cashbook.type', model_name='cashbook.type',
states={ states={
'required': Eval('eval_dtype', '') == 'types', 'required': Eval('eval_dtype', '').in_(booktype_types),
}, depends=['eval_dtype']) }, depends=['eval_dtype'])
currency = fields.Many2One(string='Currency', select=True, ondelete='CASCADE', currency = fields.Many2One(string='Currency', select=True, ondelete='CASCADE',
model_name='currency.currency', model_name='currency.currency',
states={ states={
'required': Eval('eval_dtype', '') == 'currencies', 'required': Eval('eval_dtype', '') == 'currencies',
}, depends=['eval_dtype']) }, depends=['eval_dtype'])
category = fields.Many2One(string='Category', select=True, ondelete='CASCADE',
model_name='cashbook.bookcategory',
states={
'required': Eval('eval_dtype', '').in_(category_types),
}, depends=['eval_dtype'])
# dtype + currency of evaluation # dtype + currency of evaluation
eval_dtype = fields.Function(fields.Char(string='Data type', readonly=True), eval_dtype = fields.Function(fields.Char(string='Data type', readonly=True),
@ -74,7 +80,7 @@ class EvaluationLine(ModelSQL, ModelView):
# get id of origin chart-form # get id of origin chart-form
form_id = ModelData.get_id('cashbook_report', 'evalline_view_graph') form_id = ModelData.get_id('cashbook_report', 'evalline_view_graph')
# active_chart was added by tree_open-action # active_evaluation was added by tree_open-action
active_evaluation = context.get('active_evaluation', None) active_evaluation = context.get('active_evaluation', None)
# check if we are requested for our default form... # check if we are requested for our default form...
@ -90,7 +96,7 @@ class EvaluationLine(ModelSQL, ModelView):
@fields.depends('evaluation', '_parent_evaluation.dtype') @fields.depends('evaluation', '_parent_evaluation.dtype')
def on_change_with_eval_dtype(self, name=None): def on_change_with_eval_dtype(self, name=None):
""" get dtape from parent """ get dtype from parent
""" """
if self.evaluation: if self.evaluation:
return self.evaluation.dtype return self.evaluation.dtype
@ -111,7 +117,7 @@ class EvaluationLine(ModelSQL, ModelView):
else: else:
return 2 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): def on_change_with_name(self, name=None):
""" get name of Type """ get name of Type
""" """
@ -122,27 +128,40 @@ class EvaluationLine(ModelSQL, ModelView):
# otherwise use rec_name of linked record # otherwise use rec_name of linked record
if self.eval_dtype: if self.eval_dtype:
dtype_sel = {'currencies': 'currency'}
dtype_sel.update({x:'cashbook' for x in cashbook_types})
dtype_sel.update({x:'category' for x in category_types})
dtype_sel.update({x:'dtype' for x in booktype_types})
return getattr( return getattr(
getattr(self, { getattr(self, dtype_sel[self.eval_dtype], None),
'cashbooks': 'cashbook',
'types': 'dtype',
'currencies': 'currency',
}[self.eval_dtype], None),
'rec_name', None) 'rec_name', None)
def convert_to_evalcurrency(self, from_currency, amount):
""" convert amount to current evaluation-currency
"""
Currency = Pool().get('currency.currency')
exp = Decimal(Decimal(1) / 10 ** self.currency_digits)
return Currency.compute(
from_currency,
amount,
self.eval_currency,
).quantize(exp)
@classmethod @classmethod
def validate(cls, records): def validate(cls, records):
""" check parent record """ check parent record
""" """
super(EvaluationLine, cls).validate(records) super(EvaluationLine, cls).validate(records)
for record in records: for record in records:
if (record.evaluation.dtype != 'cashbooks') and \ if (record.evaluation.dtype not in cashbook_types) and \
(record.cashbook is not None): (record.cashbook is not None):
raise UserError(gettext( raise UserError(gettext(
'cashbook_report.msg_invalid_dtype', 'cashbook_report.msg_invalid_dtype',
typename = gettext('cashbook_report.msg_dtype_cashbook'), typename = gettext('cashbook_report.msg_dtype_cashbook'),
)) ))
if (record.evaluation.dtype != 'types') and \ if (record.evaluation.dtype not in booktype_types) and \
(record.dtype is not None): (record.dtype is not None):
raise UserError(gettext( raise UserError(gettext(
'cashbook_report.msg_invalid_dtype', 'cashbook_report.msg_invalid_dtype',
@ -154,23 +173,16 @@ class EvaluationLine(ModelSQL, ModelView):
'cashbook_report.msg_invalid_dtype', 'cashbook_report.msg_invalid_dtype',
typename = gettext('cashbook_report.msg_dtype_currency'), typename = gettext('cashbook_report.msg_dtype_currency'),
)) ))
if (record.evaluation.dtype not in category_types) and \
(record.category is not None):
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
typename = gettext('cashbook_report.msg_dtype_category'),
))
def get_value_cashbooks(self): def get_balance_by_query(self, query):
""" balance of cashbooks """ run 'query' on Lines, convert used
""" currencies to evaluation-currency
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() pool = Pool()
Lines = pool.get('cashbook.line') Lines = pool.get('cashbook.line')
@ -180,19 +192,11 @@ class EvaluationLine(ModelSQL, ModelView):
tab_book = Cashbook.__table__() tab_book = Cashbook.__table__()
cursor = Transaction().connection.cursor() 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') total_amount = Decimal('0.0')
with Transaction().set_context({ with Transaction().set_context({
'_check_access': True, '_check_access': True,
}): }):
lines = Lines.search([ lines = Lines.search(query, query=True)
('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, query = lines.join(tab_line, condition=lines.id==tab_line.id,
).join(tab_book, condition=tab_book.id==tab_line.cashbook, ).join(tab_book, condition=tab_book.id==tab_line.cashbook,
@ -203,69 +207,80 @@ class EvaluationLine(ModelSQL, ModelView):
) )
cursor.execute(*query) cursor.execute(*query)
balances = cursor.fetchall() balances = cursor.fetchall()
for balance in balances: for balance in balances:
(id_currency, bal1) = balance (id_currency, bal1) = balance
if bal1 is not None: if bal1 is not None:
total_amount += Currency.compute( total_amount += self.convert_to_evalcurrency(
Currency(id_currency), Currency(id_currency), bal1)
bal1, return total_amount
self.eval_currency,
) def get_value_cashbooks(self):
exp = Decimal(Decimal(1) / 10 ** self.currency_digits) """ balance of cashbooks
return total_amount.quantize(exp) """
Currency = Pool().get('currency.currency')
if self.cashbook:
return self.convert_to_evalcurrency(
self.cashbook.currency,
self.cashbook.balance,
)
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): def get_value_currencies(self):
""" get balance of bookings in cashbooks by 'currency', """ get balance of bookings in cashbooks by 'currency',
converted to currency of evaluation converted to currency of evaluation
""" """
pool = Pool() IrDate = Pool().get('ir.date')
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 \ if self.currency is None:
(self.eval_currency is None) or (self.currency_digits is None):
return None return None
total_amount = Decimal('0.0') return self.get_balance_by_query([
with Transaction().set_context({
'_check_access': True,
}):
lines = Lines.search([
('cashbook.currency.id', '=', self.currency.id), ('cashbook.currency.id', '=', self.currency.id),
('cashbook.state', '=', 'open'), ('cashbook.state', '=', 'open'),
('cashbook.owner.id', '=', Transaction().user), ('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', \ @fields.depends('eval_dtype', 'eval_currency', 'currency_digits', \
'cashbook', '_parent_cashbook.currency', '_parent_cashbook.balance',\ 'cashbook', '_parent_cashbook.currency', '_parent_cashbook.balance',\
'category', '_parent_category.id',
'evaluation', '_parent_evaluation.id', 'dtype', 'currency') 'evaluation', '_parent_evaluation.id', 'dtype', 'currency')
def on_change_with_balance(self, name=None): def on_change_with_balance(self, name=None):
""" balance of cashbook """ balance of cashbook
""" """
if self.eval_dtype: if (self.evaluation is None) or (self.eval_currency is None) or \
return getattr(self, 'get_value_%s' % self.eval_dtype)() (self.currency_digits is None) or (self.eval_dtype is None):
return None
return getattr(self, 'get_value_%s' % self.eval_dtype)()
# end EvaluationLine # end EvaluationLine

View file

@ -11,17 +11,57 @@ msgid "Type of evaluation must be '%(typename)s'."
msgstr "Typ der Auswertung mus '%(typename)s' sein." msgstr "Typ der Auswertung mus '%(typename)s' sein."
msgctxt "model:ir.message,text:msg_dtype_cashbook" msgctxt "model:ir.message,text:msg_dtype_cashbook"
msgid "Cashbooks" msgid "Cashbooks [Amount]"
msgstr "Kassenbücher" msgstr "Kassenbücher [Betrag]"
msgctxt "model:ir.message,text:msg_dtype_cashbook_gldiff"
msgid "Cashbooks [Amount of Profit/Loss]"
msgstr "Kassenbücher [Betrag Gewinn/Verlust]"
msgctxt "model:ir.message,text:msg_dtype_cashbook_glperc"
msgid "Cashbooks [Percent of Profit/Loss]"
msgstr "Kassenbücher [Prozent Gewinn/Verlust]"
msgctxt "model:ir.message,text:msg_dtype_cashbooks_glvalue"
msgid "Cashbooks [Current Value]"
msgstr "Kassenbücher [aktueller Wert]"
msgctxt "model:ir.message,text:msg_dtype_type" msgctxt "model:ir.message,text:msg_dtype_type"
msgid "Types of Cashbooks" msgid "Types of Cashbooks [Amount]"
msgstr "Typen von Kassenbüchern" msgstr "Typen von Kassenbüchern [Betrag]"
msgctxt "model:ir.message,text:msg_dtype_types_gldiff"
msgid "Types of Cashbooks [Amount of Profit/Loss]"
msgstr "Typen von Kassenbüchern [Betrag Gewinn/Verlust]"
msgctxt "model:ir.message,text:msg_dtype_types_glvalue"
msgid "Types of Cashbooks [Current Value]"
msgstr "Typen von Kassenbüchern [aktueller Wert]"
msgctxt "model:ir.message,text:msg_dtype_types_glperc"
msgid "Types of Cashbooks [Percent of Profit/Loss]"
msgstr "Typen von Kassenbüchern [Prozent Gewinn/Verlust]"
msgctxt "model:ir.message,text:msg_dtype_currency" msgctxt "model:ir.message,text:msg_dtype_currency"
msgid "Currencies" msgid "Currencies"
msgstr "Währungen" msgstr "Währungen"
msgctxt "model:ir.message,text:msg_dtype_category"
msgid "Categories [Amount]"
msgstr "Kategorien [Betrag]"
msgctxt "model:ir.message,text:msg_dtype_category_gldiff"
msgid "Categories [Amount of Profit/Loss]"
msgstr "Kategorien [Betrag Gewinn/Verlust]"
msgctxt "model:ir.message,text:msg_dtype_category_glvalue"
msgid "Categories [Current Value]"
msgstr "Kategorien [aktueller Wert]"
msgctxt "model:ir.message,text:msg_dtype_category_glperc"
msgid "Categories [Percent of Profit/Loss]"
msgstr "Kategorien [Prozent Gewinn/Verlust]"
msgctxt "model:ir.message,text:msg_name_graph" msgctxt "model:ir.message,text:msg_name_graph"
msgid "Graph: %(gname)s" msgid "Graph: %(gname)s"
msgstr "Diagramm: %(gname)s" msgstr "Diagramm: %(gname)s"
@ -134,6 +174,10 @@ msgctxt "selection:cashbook_report.evaluation,dtype:"
msgid "Currencys" msgid "Currencys"
msgstr "Währungen" msgstr "Währungen"
msgctxt "selection:cashbook_report.evaluation,dtype:"
msgid "Categories"
msgstr "Kategorien"
msgctxt "help:cashbook_report.evaluation,dtype:" msgctxt "help:cashbook_report.evaluation,dtype:"
msgid "Type of data displayed" msgid "Type of data displayed"
msgstr "Art der dargestellten Daten" msgstr "Art der dargestellten Daten"
@ -226,6 +270,10 @@ msgctxt "field:cashbook_report.evaluation,currencies:"
msgid "Currencies" msgid "Currencies"
msgstr "Währungen" msgstr "Währungen"
msgctxt "field:cashbook_report.evaluation,categories:"
msgid "Categories"
msgstr "Kategorien"
msgctxt "field:cashbook_report.evaluation,line_values:" msgctxt "field:cashbook_report.evaluation,line_values:"
msgid "Line Values" msgid "Line Values"
msgstr "Zeilenwerte" msgstr "Zeilenwerte"

View file

@ -7,17 +7,57 @@ msgid "Type of evaluation must be '%(typename)s'."
msgstr "Type of evaluation must be '%(typename)s'." msgstr "Type of evaluation must be '%(typename)s'."
msgctxt "model:ir.message,text:msg_dtype_cashbook" msgctxt "model:ir.message,text:msg_dtype_cashbook"
msgid "Cashbooks" msgid "Cashbooks [Amount]"
msgstr "Cashbooks" msgstr "Cashbooks [Amount]"
msgctxt "model:ir.message,text:msg_dtype_cashbook_gldiff"
msgid "Cashbooks [Amount of Profit/Loss]"
msgstr "Cashbooks [Amount of Profit/Loss]"
msgctxt "model:ir.message,text:msg_dtype_cashbook_glperc"
msgid "Cashbooks [Percent of Profit/Loss]"
msgstr "Cashbooks [Percent of Profit/Loss]"
msgctxt "model:ir.message,text:msg_dtype_cashbooks_glvalue"
msgid "Cashbooks [Current Value]"
msgstr "Cashbooks [Current Value]"
msgctxt "model:ir.message,text:msg_dtype_type" msgctxt "model:ir.message,text:msg_dtype_type"
msgid "Types of Cashbooks" msgid "Types of Cashbooks [Amount]"
msgstr "Types of Cashbooks" msgstr "Types of Cashbooks [Amount]"
msgctxt "model:ir.message,text:msg_dtype_types_gldiff"
msgid "Types of Cashbooks [Amount of Profit/Loss]"
msgstr "Types of Cashbooks [Amount of Profit/Loss]"
msgctxt "model:ir.message,text:msg_dtype_types_glvalue"
msgid "Types of Cashbooks [Current Value]"
msgstr "Types of Cashbooks [Current Value]"
msgctxt "model:ir.message,text:msg_dtype_types_glperc"
msgid "Types of Cashbooks [Percent of Profit/Loss]"
msgstr "Types of Cashbooks [Percent of Profit/Loss]"
msgctxt "model:ir.message,text:msg_dtype_currency" msgctxt "model:ir.message,text:msg_dtype_currency"
msgid "Currencies" msgid "Currencies"
msgstr "Currencies" msgstr "Currencies"
msgctxt "model:ir.message,text:msg_dtype_category"
msgid "Categories [Amount]"
msgstr "Categories [Amount]"
msgctxt "model:ir.message,text:msg_dtype_category_gldiff"
msgid "Categories [Amount of Profit/Loss]"
msgstr "Categories [Amount of Profit/Loss]"
msgctxt "model:ir.message,text:msg_dtype_category_glvalue"
msgid "Categories [Current Value]"
msgstr "Categories [Current Value]"
msgctxt "model:ir.message,text:msg_dtype_category_glperc"
msgid "Categories [Percent of Profit/Loss]"
msgstr "Categories [Percent of Profit/Loss]"
msgctxt "model:ir.message,text:msg_name_graph" msgctxt "model:ir.message,text:msg_name_graph"
msgid "Graph: %(gname)s" msgid "Graph: %(gname)s"
msgstr "Graph: %(gname)s" msgstr "Graph: %(gname)s"
@ -114,6 +154,10 @@ msgctxt "selection:cashbook_report.evaluation,dtype:"
msgid "Currencys" msgid "Currencys"
msgstr "Currencys" msgstr "Currencys"
msgctxt "selection:cashbook_report.evaluation,dtype:"
msgid "Categories"
msgstr "Categories"
msgctxt "help:cashbook_report.evaluation,dtype:" msgctxt "help:cashbook_report.evaluation,dtype:"
msgid "Type of data displayed" msgid "Type of data displayed"
msgstr "Type of data displayed" msgstr "Type of data displayed"
@ -206,6 +250,10 @@ msgctxt "field:cashbook_report.evaluation,currencies:"
msgid "Currencies" msgid "Currencies"
msgstr "Currencies" msgstr "Currencies"
msgctxt "field:cashbook_report.evaluation,categories:"
msgid "Categories"
msgstr "Categories"
msgctxt "field:cashbook_report.evaluation,line_values:" msgctxt "field:cashbook_report.evaluation,line_values:"
msgid "Line Values" msgid "Line Values"
msgstr "Line Values" msgstr "Line Values"

View file

@ -9,14 +9,44 @@ full copyright notices and license terms. -->
<field name="text">Type of evaluation must be '%(typename)s'.</field> <field name="text">Type of evaluation must be '%(typename)s'.</field>
</record> </record>
<record model="ir.message" id="msg_dtype_cashbook"> <record model="ir.message" id="msg_dtype_cashbook">
<field name="text">Cashbooks</field> <field name="text">Cashbooks [Amount]</field>
</record>
<record model="ir.message" id="msg_dtype_cashbook_gldiff">
<field name="text">Cashbooks [Amount of Profit/Loss]</field>
</record>
<record model="ir.message" id="msg_dtype_cashbook_glperc">
<field name="text">Cashbooks [Percent of Profit/Loss]</field>
</record>
<record model="ir.message" id="msg_dtype_cashbooks_glvalue">
<field name="text">Cashbooks [Current Value]</field>
</record> </record>
<record model="ir.message" id="msg_dtype_type"> <record model="ir.message" id="msg_dtype_type">
<field name="text">Types of Cashbooks</field> <field name="text">Types of Cashbooks [Amount]</field>
</record>
<record model="ir.message" id="msg_dtype_types_gldiff">
<field name="text">Types of Cashbooks [Amount of Profit/Loss]</field>
</record>
<record model="ir.message" id="msg_dtype_types_glvalue">
<field name="text">ypes of Cashbooks [Current Value]</field>
</record>
<record model="ir.message" id="msg_dtype_types_glperc">
<field name="text">Types of Cashbooks [Percent of Profit/Loss]</field>
</record> </record>
<record model="ir.message" id="msg_dtype_currency"> <record model="ir.message" id="msg_dtype_currency">
<field name="text">Currencies</field> <field name="text">Currencies</field>
</record> </record>
<record model="ir.message" id="msg_dtype_category">
<field name="text">Categories [Amount]</field>
</record>
<record model="ir.message" id="msg_dtype_category_gldiff">
<field name="text">Categories [Amount of Profit/Loss]</field>
</record>
<record model="ir.message" id="msg_dtype_category_glvalue">
<field name="text">Categories [Current Value]</field>
</record>
<record model="ir.message" id="msg_dtype_category_glperc">
<field name="text">Categories [Percent of Profit/Loss]</field>
</record>
<record model="ir.message" id="msg_name_graph"> <record model="ir.message" id="msg_name_graph">
<field name="text">Graph: %(gname)s</field> <field name="text">Graph: %(gname)s</field>
</record> </record>

View file

@ -22,7 +22,7 @@ with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
# tryton.cfg einlesen # tryton.cfg einlesen
config = ConfigParser() config = ConfigParser()
config.readfp(open('tryton.cfg')) config.read_file(open('tryton.cfg'))
info = dict(config.items('tryton')) info = dict(config.items('tryton'))
for key in ('depends', 'extras_depend', 'xml'): for key in ('depends', 'extras_depend', 'xml'):
if key in info: if key in info:
@ -68,6 +68,7 @@ setup(name='%s_%s' % (PREFIX, MODULE),
description='Tryton module to add reports to cashbook.', description='Tryton module to add reports to cashbook.',
long_description=long_description, long_description=long_description,
url='https://www.m-ds.de/', url='https://www.m-ds.de/',
download_url='https://scmdev.m-ds.de/Tryton/Extra/cashbook_report',
author='martin-data services', author='martin-data services',
author_email='service@m-ds.de', author_email='service@m-ds.de',
license='GPL-3', license='GPL-3',

View file

@ -3,6 +3,9 @@
# The COPYRIGHT file at the top level of this repository contains the # The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms. # full copyright notices and license terms.
cashbook_types = ['cashbooks', 'cashbooks_gldiff', 'cashbooks_glperc', 'cashbooks_glvalue']
category_types = ['categories', 'category_gldiff', 'category_glvalue', 'category_glperc']
booktype_types = ['types', 'types_gldiff', 'types_glvalue', 'types_glperc']
template_view_line = '<field name="balance" fill="%(fill)s" empty="0" string="%(string)s"/>' template_view_line = '<field name="balance" fill="%(fill)s" empty="0" string="%(string)s"/>'

View file

@ -3,7 +3,7 @@
# The COPYRIGHT file at the top level of this repository contains the # The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms. # full copyright notices and license terms.
from trytond.tests.test_tryton import ModuleTestCase, with_transaction from trytond.tests.test_tryton import ModuleTestCase, with_transaction, activate_module
from trytond.pool import Pool from trytond.pool import Pool
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.exceptions import UserError from trytond.exceptions import UserError
@ -16,6 +16,13 @@ class ReportTestCase(CashbookTestCase):
'Test cashbook book report module' 'Test cashbook book report module'
module = 'cashbook_report' module = 'cashbook_report'
@classmethod
def setUpClass(cls):
""" add modelues
"""
super(ReportTestCase, cls).setUpClass()
activate_module(['dashboard', 'cashbook_investment'])
def prep_report_3books(self): def prep_report_3books(self):
""" create 3x cashbooks, add bookings, """ create 3x cashbooks, add bookings,
""" """
@ -230,6 +237,15 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(books_owner1[1].name, 'Book 2') self.assertEqual(books_owner1[1].name, 'Book 2')
self.assertEqual(books_owner1[1].balance, Decimal('12.5')) 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([{ evaluation1, = Evaluation.create([{
'name': 'Evaluation User 1 - Cashbooks', 'name': 'Evaluation User 1 - Cashbooks',
'dtype': 'cashbooks', 'dtype': 'cashbooks',
@ -269,6 +285,19 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(evaluation3.line_values[1].name, 'usd') self.assertEqual(evaluation3.line_values[1].name, 'usd')
self.assertEqual(evaluation3.line_values[1].balance, Decimal('35.71')) self.assertEqual(evaluation3.line_values[1].balance, Decimal('35.71'))
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_user(users[1].id):
with Transaction().set_context({ with Transaction().set_context({
'_check_access': True, '_check_access': True,
@ -278,6 +307,15 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(len(books_owner2), 1) self.assertEqual(len(books_owner2), 1)
self.assertEqual(books_owner2[0].name, 'Book 3') 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([{ evaluation1, = Evaluation.create([{
'name': 'Evaluation User 2 - Cashbooks', 'name': 'Evaluation User 2 - Cashbooks',
'dtype': 'cashbooks', 'dtype': 'cashbooks',
@ -303,7 +341,7 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(evaluation2.line_values[1].balance, Decimal('0.0')) self.assertEqual(evaluation2.line_values[1].balance, Decimal('0.0'))
evaluation3, = Evaluation.create([{ evaluation3, = Evaluation.create([{
'name': 'Evaluation User 3 - Currencies', 'name': 'Evaluation User 2 - Currencies',
'dtype': 'currencies', 'dtype': 'currencies',
'currencies': [('add', [x.id for x in Currency.search([])])], 'currencies': [('add', [x.id for x in Currency.search([])])],
}]) }])
@ -315,6 +353,90 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(evaluation3.line_values[1].name, 'usd') self.assertEqual(evaluation3.line_values[1].name, 'usd')
self.assertEqual(evaluation3.line_values[1].balance, Decimal('0.0')) self.assertEqual(evaluation3.line_values[1].balance, Decimal('0.0'))
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 8 evaluations
evaluations = Evaluation.search([], order=[('name', 'ASC')])
self.assertEqual(len(evaluations), 8)
self.assertEqual(evaluations[0].name, 'Evaluation User 1 - Cashbooks')
self.assertEqual(len(evaluations[0].cashbooks), 2)
self.assertEqual(evaluations[0].currency.rec_name, 'Euro')
self.assertEqual(len(evaluations[0].line_values), 2)
self.assertEqual(evaluations[0].line_values[0].name, 'Book 1 | 25.00 usd | Open')
self.assertEqual(evaluations[0].line_values[0].balance, Decimal('23.81'))
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 - Categories')
self.assertEqual(len(evaluations[1].categories), 1)
self.assertEqual(evaluations[1].currency.rec_name, 'Euro')
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 - 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, 'Euro')
self.assertEqual(evaluations[2].line_values[0].balance, Decimal('23.0'))
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 1 - Types')
self.assertEqual(len(evaluations[3].types), 2)
self.assertEqual(evaluations[3].currency.rec_name, 'Euro')
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 - Cashbooks')
self.assertEqual(len(evaluations[4].cashbooks), 1)
self.assertEqual(evaluations[4].currency.rec_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[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), 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[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() @with_transaction()
def test_report_update_name_of_line(self): def test_report_update_name_of_line(self):
""" check replace rec_name-value on line with """ check replace rec_name-value on line with
@ -367,6 +489,7 @@ class ReportTestCase(CashbookTestCase):
Evaluation = pool.get('cashbook_report.evaluation') Evaluation = pool.get('cashbook_report.evaluation')
Types = pool.get('cashbook.type') Types = pool.get('cashbook.type')
Currency = pool.get('currency.currency') Currency = pool.get('currency.currency')
Category = pool.get('cashbook.bookcategory')
books = self.prep_report_3books() books = self.prep_report_3books()
@ -374,6 +497,15 @@ class ReportTestCase(CashbookTestCase):
with Transaction().set_context({ with Transaction().set_context({
'company': company.id, 'company': company.id,
}): }):
categories = Category.create([{
'name': 'Cat 1',
}, {
'name': 'Cat 2',
}, {
'name': 'Cat 3',
}])
# valid # valid
evaluation, = Evaluation.create([{ evaluation, = Evaluation.create([{
'name': 'Evaluation 1', 'name': 'Evaluation 1',
@ -383,6 +515,32 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(len(evaluation.cashbooks), 3) self.assertEqual(len(evaluation.cashbooks), 3)
self.assertEqual(len(evaluation.types), 0) self.assertEqual(len(evaluation.types), 0)
self.assertEqual(len(evaluation.currencies), 0) self.assertEqual(len(evaluation.currencies), 0)
self.assertEqual(len(evaluation.categories), 0)
# investment - profit/loss amount
if 'cashbooks_gldiff' in [x[0] for x in Evaluation.get_sel_etype()]:
# no change if switch between cashbook-types
Evaluation.write(*[
[evaluation],
{
'dtype': 'cashbooks_gldiff',
}])
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],
{
'dtype': 'cashbooks_glperc',
}])
self.assertEqual(len(evaluation.cashbooks), 3)
self.assertEqual(len(evaluation.types), 0)
self.assertEqual(len(evaluation.currencies), 0)
self.assertEqual(len(evaluation.categories), 0)
else :
print('\n--== Module "cashbook_investment" not installed ==--')
Evaluation.write(*[ Evaluation.write(*[
[evaluation], [evaluation],
@ -393,6 +551,7 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(len(evaluation.cashbooks), 0) self.assertEqual(len(evaluation.cashbooks), 0)
self.assertEqual(len(evaluation.types), 2) self.assertEqual(len(evaluation.types), 2)
self.assertEqual(len(evaluation.currencies), 0) self.assertEqual(len(evaluation.currencies), 0)
self.assertEqual(len(evaluation.categories), 0)
# write same dtype again - no change # write same dtype again - no change
Evaluation.write(*[ Evaluation.write(*[
@ -403,6 +562,7 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(len(evaluation.cashbooks), 0) self.assertEqual(len(evaluation.cashbooks), 0)
self.assertEqual(len(evaluation.types), 2) self.assertEqual(len(evaluation.types), 2)
self.assertEqual(len(evaluation.currencies), 0) self.assertEqual(len(evaluation.currencies), 0)
self.assertEqual(len(evaluation.categories), 0)
Evaluation.write(*[ Evaluation.write(*[
[evaluation], [evaluation],
@ -413,6 +573,18 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(len(evaluation.cashbooks), 0) self.assertEqual(len(evaluation.cashbooks), 0)
self.assertEqual(len(evaluation.types), 0) self.assertEqual(len(evaluation.types), 0)
self.assertEqual(len(evaluation.currencies), 2) 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.write(*[
[evaluation], [evaluation],
@ -422,6 +594,7 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(len(evaluation.cashbooks), 0) self.assertEqual(len(evaluation.cashbooks), 0)
self.assertEqual(len(evaluation.types), 0) self.assertEqual(len(evaluation.types), 0)
self.assertEqual(len(evaluation.currencies), 0) self.assertEqual(len(evaluation.currencies), 0)
self.assertEqual(len(evaluation.categories), 0)
@with_transaction() @with_transaction()
def test_report_dtype_validation(self): def test_report_dtype_validation(self):
@ -470,6 +643,278 @@ class ReportTestCase(CashbookTestCase):
'types': [('add', [x.id for x in Types.search([])])], 'types': [('add', [x.id for x in Types.search([])])],
}]) }])
@with_transaction()
def test_report_check_update_of_actionviews(self):
""" create 3x cashbooks, add evaluation, check created
form + actionview
"""
pool = Pool()
Evaluation = pool.get('cashbook_report.evaluation')
try :
DashboardAction = pool.get('dashboard.action')
except:
print('\n--== Module "dashboard" not installed ==--')
DashboardAction = None
books = self.prep_report_3books()
company = self.prep_company()
with Transaction().set_context({
'company': company.id,
}):
evaluation, = Evaluation.create([{
'name': 'Evaluation 1',
'cashbooks': [('add', [x.id for x in books])],
}])
# add dashboard-action
if DashboardAction is not None:
dbaction, = DashboardAction.create([{
'user': Transaction().user,
'act_window': evaluation.dashb_actwin.id,
}])
self.assertEqual(dbaction.user.rec_name, 'Administrator')
self.assertEqual(dbaction.act_window.name, 'Evaluation 1')
self.assertEqual(evaluation.dtype, 'cashbooks')
self.assertEqual(evaluation.chart, 'pie')
self.assertEqual(evaluation.legend, True)
self.assertEqual(evaluation.maincolor, 'default')
self.assertEqual(evaluation.bgcolor, '#ffffc0')
self.assertEqual(evaluation.currency.code, 'EUR')
# check uiview
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')
# action-window for dashbord
self.assertEqual(evaluation.dashb_actwin.name, 'Evaluation 1')
self.assertEqual(evaluation.dashb_actwin.res_model,
'cashbook_report.eval_line')
self.assertEqual(evaluation.dashb_actwin.usage,
'dashboard')
self.assertEqual(evaluation.dashb_actwin.domain,
'[["evaluation", "=", %d]]' % evaluation.id)
# action-view
self.assertEqual(evaluation.dashb_actview.sequence, 10)
self.assertEqual(evaluation.dashb_actview.view.id,
evaluation.ui_view_chart.id)
self.assertEqual(evaluation.dashb_actview.act_window.id,
evaluation.dashb_actwin.id)
# update evaluation, this wil re-create the view/act-window
# and update the dashboard-view, without removing it
old_win_id = evaluation.dashb_actwin.id
Evaluation.write(*[
[evaluation],
{
'name': 'Evaluation 1a',
}])
self.assertTrue(old_win_id != evaluation.dashb_actwin.id)
if DashboardAction is not None:
self.assertEqual(DashboardAction.search_count([]), 1)
@with_transaction()
def test_report_chart_hbar_book_investment(self):
""" create 3x cashbooks, add bookings, rates
create report with cashbooks, check
"""
pool = Pool()
Evaluation = pool.get('cashbook_report.evaluation')
Book = pool.get('cashbook.book')
company = self.prep_company()
with Transaction().set_context({
'company': company.id,
}):
if 'cashbooks_gldiff' not in [x[0] for x in Evaluation.get_sel_etype()]:
print('\n--== Module "cashbook_investment" not installed ==--')
return
AccType = pool.get('cashbook.type')
Asset = pool.get('investment.asset')
Product = pool.get('product.template')
Uom = pool.get('product.uom')
CbCategory = pool.get('cashbook.bookcategory')
at, = AccType.create([{
'name': 'depot',
'short': 'D',
'feature': 'asset',
'company': company.id,
}])
prod_templ, = Product.create([{
'name': 'Aurum',
'type': 'assets',
'list_price': Decimal('1.0'),
'default_uom': Uom.search([('symbol', '=', 'u')])[0].id,
'products': [('create', [{
'description': 'Au',
}])],
}])
asset, = Asset.create([{
'company': company.id,
'product': prod_templ.products[0].id,
'currency': company.currency.id,
'currency_digits': 4,
'uom': prod_templ.default_uom.id,
'rates': [('create', [{
'date': date(2022, 5, 1),
'rate': Decimal('1750.0'),
}, ])],
}])
self.assertEqual(asset.rec_name,
'Aurum | 1,750.0000 usd/u | 05/01/2022')
books = self.prep_report_3books()
cb_cat, = CbCategory.create([{'name': 'CB Category'}])
Book.write(*[
books,
{
'btype': at.id,
'asset': asset.id,
'categories': [('add', [cb_cat.id])],
'quantity_uom': asset.uom.id,
'quantity_digits': 3,
'lines': [('write',
[books[0].lines[0].id], # usd
{'quantity': Decimal('2.0'), 'amount': Decimal('3000.0')},
[books[0].lines[1].id],
{'quantity': Decimal('2.0'), 'amount': Decimal('3100.0')},
[books[1].lines[0].id], # usd
{'quantity': Decimal('2.0'), 'amount': Decimal('3200.0')},
[books[1].lines[1].id],
{'quantity': Decimal('2.0'), 'amount': Decimal('3300.0')},
[books[2].lines[0].id], # euro
{'quantity': Decimal('2.0'), 'amount': Decimal('3300.0')},
[books[2].lines[1].id],
{'quantity': Decimal('2.0'), 'amount': Decimal('3400.0')},
)],
}])
self.assertEqual(books[0].rec_name, 'Book 1 | 6,100.00 usd | Open | 4.000 u')
self.assertEqual(books[0].current_value, Decimal('7000.0'))
self.assertEqual(books[0].diff_amount, Decimal('900.0'))
self.assertEqual(books[0].diff_percent, Decimal('14.75'))
self.assertEqual(books[1].rec_name, 'Book 2 | 6,500.00 usd | Open | 4.000 u')
self.assertEqual(books[1].current_value, Decimal('7000.0'))
self.assertEqual(books[1].diff_amount, Decimal('500.0'))
self.assertEqual(books[1].diff_percent, Decimal('7.69'))
self.assertEqual(books[2].rec_name, 'Book 3 | 6,700.00 € | Open | 4.000 u')
self.assertEqual(books[2].current_value, Decimal('6666.67'))
self.assertEqual(books[2].diff_amount, Decimal('-33.33'))
self.assertEqual(books[2].diff_percent, Decimal('-0.5'))
# evaluation: amount-difference
evaluation, = Evaluation.create([{
'name': 'Evaluation 1',
'dtype': 'cashbooks_gldiff',
'chart': 'hbar',
'cashbooks': [('add', [x.id for x in books])],
}])
self.assertEqual(evaluation.dtype, 'cashbooks_gldiff')
self.assertEqual(evaluation.chart, 'hbar')
self.assertEqual(evaluation.legend, True)
self.assertEqual(evaluation.maincolor, 'default')
self.assertEqual(evaluation.bgcolor, '#ffffc0')
self.assertEqual(evaluation.currency.code, 'EUR')
self.assertEqual(evaluation.line_values[0].balance, Decimal('857.14'))
self.assertEqual(evaluation.line_values[1].balance, Decimal('476.19'))
self.assertEqual(evaluation.line_values[2].balance, Decimal('-33.33'))
# evaluation: percent-difference
evaluation2, = Evaluation.create([{
'name': 'Evaluation 2',
'dtype': 'cashbooks_glperc',
'chart': 'hbar',
'cashbooks': [('add', [x.id for x in books])],
}])
self.assertEqual(evaluation2.dtype, 'cashbooks_glperc')
self.assertEqual(evaluation2.chart, 'hbar')
self.assertEqual(evaluation2.legend, True)
self.assertEqual(evaluation2.maincolor, 'default')
self.assertEqual(evaluation2.bgcolor, '#ffffc0')
self.assertEqual(evaluation2.currency.code, 'EUR')
self.assertEqual(evaluation2.line_values[0].balance, Decimal('14.75'))
self.assertEqual(evaluation2.line_values[1].balance, Decimal('7.69'))
self.assertEqual(evaluation2.line_values[2].balance, Decimal('-0.5'))
# evaluation: percent-difference
evaluation3, = Evaluation.create([{
'name': 'Evaluation 3',
'dtype': 'cashbooks_glvalue',
'chart': 'hbar',
'cashbooks': [('add', [x.id for x in books])],
}])
self.assertEqual(evaluation3.dtype, 'cashbooks_glvalue')
self.assertEqual(evaluation3.chart, 'hbar')
self.assertEqual(evaluation3.legend, True)
self.assertEqual(evaluation3.maincolor, 'default')
self.assertEqual(evaluation3.bgcolor, '#ffffc0')
self.assertEqual(evaluation3.currency.code, 'EUR')
self.assertEqual(evaluation3.line_values[0].balance, Decimal('6666.67'))
self.assertEqual(evaluation3.line_values[1].balance, Decimal('6666.67'))
self.assertEqual(evaluation3.line_values[2].balance, Decimal('6666.67'))
# evaluation: category-current value
evaluation4, = Evaluation.create([{
'name': 'Evaluation 4',
'dtype': 'category_glvalue',
'chart': 'hbar',
'categories': [('add', [cb_cat.id])],
}])
self.assertEqual(evaluation4.dtype, 'category_glvalue')
self.assertEqual(evaluation4.chart, 'hbar')
self.assertEqual(evaluation4.legend, True)
self.assertEqual(evaluation4.maincolor, 'default')
self.assertEqual(evaluation4.bgcolor, '#ffffc0')
self.assertEqual(evaluation4.currency.code, 'EUR')
self.assertEqual(len(evaluation4.line_values), 1)
self.assertEqual(evaluation4.line_values[0].balance, Decimal('20000.01'))
# evaluation: category- difference amount
evaluation5, = Evaluation.create([{
'name': 'Evaluation 5',
'dtype': 'category_gldiff',
'chart': 'hbar',
'categories': [('add', [cb_cat.id])],
}])
self.assertEqual(evaluation5.dtype, 'category_gldiff')
self.assertEqual(evaluation5.chart, 'hbar')
self.assertEqual(evaluation5.legend, True)
self.assertEqual(evaluation5.maincolor, 'default')
self.assertEqual(evaluation5.bgcolor, '#ffffc0')
self.assertEqual(evaluation5.currency.code, 'EUR')
self.assertEqual(len(evaluation5.line_values), 1)
self.assertEqual(evaluation5.line_values[0].balance, Decimal('1300.01'))
# evaluation: category- difference amount
evaluation6, = Evaluation.create([{
'name': 'Evaluation 6',
'dtype': 'category_glperc',
'chart': 'hbar',
'categories': [('add', [cb_cat.id])],
}])
self.assertEqual(evaluation6.dtype, 'category_glperc')
self.assertEqual(evaluation6.chart, 'hbar')
self.assertEqual(evaluation6.legend, True)
self.assertEqual(evaluation6.maincolor, 'default')
self.assertEqual(evaluation6.bgcolor, '#ffffc0')
self.assertEqual(evaluation6.currency.code, 'EUR')
self.assertEqual(len(evaluation6.line_values), 1)
self.assertEqual(evaluation6.line_values[0].balance, Decimal('6.95'))
@with_transaction() @with_transaction()
def test_report_chart_pie_book_red(self): def test_report_chart_pie_book_red(self):
""" create 3x cashbooks, add bookings, """ create 3x cashbooks, add bookings,
@ -490,7 +935,6 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(evaluation.dtype, 'cashbooks') self.assertEqual(evaluation.dtype, 'cashbooks')
self.assertEqual(evaluation.chart, 'pie') self.assertEqual(evaluation.chart, 'pie')
self.assertEqual(evaluation.legend, True) self.assertEqual(evaluation.legend, True)
self.assertEqual(evaluation.posted, False)
self.assertEqual(evaluation.maincolor, 'default') self.assertEqual(evaluation.maincolor, 'default')
self.assertEqual(evaluation.bgcolor, '#ffffc0') self.assertEqual(evaluation.bgcolor, '#ffffc0')
self.assertEqual(evaluation.currency.code, 'EUR') self.assertEqual(evaluation.currency.code, 'EUR')
@ -506,7 +950,7 @@ class ReportTestCase(CashbookTestCase):
<field name="name"/> <field name="name"/>
</x> </x>
<y> <y>
<field name="balance" fill="1" empty="0" string="Cashbooks"/> <field name="balance" fill="1" empty="0" string="Cashbooks [Amount]"/>
</y> </y>
</graph> </graph>
""") """)
@ -556,7 +1000,6 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(evaluation.dtype, 'types') self.assertEqual(evaluation.dtype, 'types')
self.assertEqual(evaluation.chart, 'pie') self.assertEqual(evaluation.chart, 'pie')
self.assertEqual(evaluation.legend, True) self.assertEqual(evaluation.legend, True)
self.assertEqual(evaluation.posted, False)
self.assertEqual(evaluation.maincolor, 'default') self.assertEqual(evaluation.maincolor, 'default')
self.assertEqual(evaluation.bgcolor, '#ffffc0') self.assertEqual(evaluation.bgcolor, '#ffffc0')
self.assertEqual(evaluation.currency.code, 'EUR') self.assertEqual(evaluation.currency.code, 'EUR')
@ -600,7 +1043,6 @@ class ReportTestCase(CashbookTestCase):
self.assertEqual(evaluation.dtype, 'currencies') self.assertEqual(evaluation.dtype, 'currencies')
self.assertEqual(evaluation.chart, 'pie') self.assertEqual(evaluation.chart, 'pie')
self.assertEqual(evaluation.legend, True) self.assertEqual(evaluation.legend, True)
self.assertEqual(evaluation.posted, False)
self.assertEqual(evaluation.maincolor, 'default') self.assertEqual(evaluation.maincolor, 'default')
self.assertEqual(evaluation.bgcolor, '#ffffc0') self.assertEqual(evaluation.bgcolor, '#ffffc0')
self.assertEqual(evaluation.currency.code, 'EUR') self.assertEqual(evaluation.currency.code, 'EUR')

View file

@ -1,8 +1,12 @@
[tryton] [tryton]
version=6.0.0 version=6.0.6
depends: depends:
res res
cashbook cashbook
cashbook_bookcategory
extras_depend:
dashboard
cashbook_investment
xml: xml:
icon.xml icon.xml
message.xml message.xml

View file

@ -1 +1,3 @@
cashbook;6.0.19;6.0.999;mds cashbook;6.0.24;6.0.999;mds
cashbook_bookcategory;6.0.3;6.0.999;mds
cashbook_investment;6.0.5;6.0.999;mds

View file

@ -20,11 +20,10 @@ full copyright notices and license terms. -->
<label name="bgcolor"/> <label name="bgcolor"/>
<field name="bgcolor"/> <field name="bgcolor"/>
<label name="posted"/>
<field name="posted"/>
<newline/> <newline/>
<field name="cashbooks" colspan="6"/> <field name="cashbooks" colspan="6"/>
<field name="types" colspan="6"/> <field name="types" colspan="6"/>
<field name="currencies" colspan="6"/> <field name="currencies" colspan="6"/>
<field name="categories" colspan="6"/>
</form> </form>

View file

@ -2,7 +2,7 @@
<!-- This file is part of the cashbook-module from m-ds for Tryton. <!-- 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 The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. --> full copyright notices and license terms. -->
<tree keyword_open="1"> <tree keyword_open="1" sequence="sequence">
<field name="name"/> <field name="name"/>
<field name="dtype"/> <field name="dtype"/>
<field name="chart"/> <field name="chart"/>