diff --git a/__init__.py b/__init__.py
index e4f23b7..4706fe2 100644
--- a/__init__.py
+++ b/__init__.py
@@ -9,6 +9,8 @@ from .line import EvaluationLine
from .currency import Currency
from .evaluation_context import EvaluationContext
from .evaluation_wizard import OpenChartWizard
+from .investment import InvestmentEvaluation, InvestmentLine
+
def register():
Pool.register(
@@ -20,3 +22,7 @@ def register():
Pool.register(
OpenChartWizard,
module='cashbook_report', type_='wizard')
+ Pool.register(
+ InvestmentEvaluation,
+ InvestmentLine,
+ module='cashbook_report', type_='model', depends=['cashbook_investment'])
diff --git a/evaluation.py b/evaluation.py
index a25238a..513fc64 100644
--- a/evaluation.py
+++ b/evaluation.py
@@ -7,17 +7,11 @@ from trytond.model import ModelView, ModelSQL, fields, sequence_ordered
from trytond.pyson import Eval
from trytond.transaction import Transaction
from trytond.pool import Pool
+from trytond.i18n import gettext
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
-sel_etype = [
- ('cashbooks', 'Cashbooks'),
- ('types', 'Types of Cashbooks'),
- ('currencies', 'Currencys'),
- ('categories', 'Categories'),
- ]
-
sel_chart = [
('vbar', 'Vertical Bars'),
('hbar', 'Horizontal Bars'),
@@ -44,7 +38,7 @@ class Evaluation(sequence_ordered(), ModelSQL, ModelView):
required=True, ondelete="RESTRICT")
name = fields.Char(string='Name', 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')
dtype_string = dtype.translated('dtype')
chart = fields.Selection(string='Chart type', required=True,
@@ -64,7 +58,7 @@ class Evaluation(sequence_ordered(), ModelSQL, ModelView):
relation_name='cashbook_report.eval_line',
origin='evaluation', target='cashbook',
states={
- 'invisible': Eval('dtype', '') != 'cashbooks',
+ 'invisible': ~Eval('dtype', '').in_(cashbook_types),
}, depends=['dtype'])
types = fields.Many2Many(string='Types',
relation_name='cashbook_report.eval_line',
@@ -143,6 +137,17 @@ class Evaluation(sequence_ordered(), ModelSQL, ModelView):
"""
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
def get_create_view_data(cls, evaluation):
""" generate dictionary to create view-xml
@@ -285,7 +290,7 @@ class Evaluation(sequence_ordered(), ModelSQL, ModelView):
continue
for dt in ['cashbooks', 'types', 'currencies', 'categories']:
- if (values['dtype'] != dt) and \
+ if (not values['dtype'].startswith(dt)) and \
(len(getattr(evaluation, dt)) > 0):
to_write.extend([
[evaluation],
diff --git a/investment.py b/investment.py
new file mode 100644
index 0000000..d67e24c
--- /dev/null
+++ b/investment.py
@@ -0,0 +1,67 @@
+# -*- 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'))
+ ])
+ return result
+
+# end InvestmentEvaluation
+
+
+class InvestmentLine(metaclass=PoolMeta):
+ __name__ = 'cashbook_report.eval_line'
+
+ 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':
+ exp = Decimal(Decimal(1) / 10 ** self.currency_digits)
+ return Currency.compute(
+ self.cashbook.currency,
+ self.cashbook.diff_amount,
+ self.eval_currency,
+ ).quantize(exp)
+
+ def get_value_cashbooks_glvalue(self):
+ """ current value of cashbooks
+ """
+ Currency = Pool().get('currency.currency')
+
+ if self.cashbook:
+ if self.cashbook.feature == 'asset':
+ exp = Decimal(Decimal(1) / 10 ** self.currency_digits)
+ return Currency.compute(
+ self.cashbook.currency,
+ self.cashbook.current_value,
+ self.eval_currency,
+ ).quantize(exp)
+
+ 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
+
+# end InvestmentLine
diff --git a/line.py b/line.py
index 78c9860..edb7b99 100644
--- a/line.py
+++ b/line.py
@@ -11,6 +11,7 @@ from trytond.transaction import Transaction
from trytond.i18n import gettext
from trytond.exceptions import UserError
from trytond.pool import Pool
+from .templates import cashbook_types
class EvaluationLine(ModelSQL, ModelView):
@@ -23,7 +24,7 @@ class EvaluationLine(ModelSQL, ModelView):
cashbook = fields.Many2One(string='Cashbook', select=True, ondelete='CASCADE',
model_name='cashbook.book',
states={
- 'required': Eval('eval_dtype', '') == 'cashbooks',
+ 'required': Eval('eval_dtype', '').in_(cashbook_types),
}, depends=['eval_dtype'])
dtype = fields.Many2One(string='Type', select=True, ondelete='CASCADE',
model_name='cashbook.type',
@@ -130,6 +131,9 @@ class EvaluationLine(ModelSQL, ModelView):
return getattr(
getattr(self, {
'cashbooks': 'cashbook',
+ 'cashbooks_gldiff': 'cashbook',
+ 'cashbooks_glperc': 'cashbook',
+ 'cashbooks_glvalue': 'cashbook',
'categories': 'category',
'types': 'dtype',
'currencies': 'currency',
@@ -142,7 +146,7 @@ class EvaluationLine(ModelSQL, ModelView):
"""
super(EvaluationLine, cls).validate(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):
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
@@ -160,6 +164,12 @@ class EvaluationLine(ModelSQL, ModelView):
'cashbook_report.msg_invalid_dtype',
typename = gettext('cashbook_report.msg_dtype_currency'),
))
+ if (record.evaluation.dtype != 'categories') and \
+ (record.category is not None):
+ raise UserError(gettext(
+ 'cashbook_report.msg_invalid_dtype',
+ typename = gettext('cashbook_report.msg_dtype_category'),
+ ))
def get_balance_by_query(self, query):
""" run 'query' on Lines, convert used
diff --git a/locale/de.po b/locale/de.po
index b770a6f..c3c2744 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -11,8 +11,20 @@ msgid "Type of evaluation must be '%(typename)s'."
msgstr "Typ der Auswertung mus '%(typename)s' sein."
msgctxt "model:ir.message,text:msg_dtype_cashbook"
-msgid "Cashbooks"
-msgstr "Kassenbücher"
+msgid "Cashbooks [Amount]"
+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"
msgid "Types of Cashbooks"
@@ -22,6 +34,10 @@ msgctxt "model:ir.message,text:msg_dtype_currency"
msgid "Currencies"
msgstr "Währungen"
+msgctxt "model:ir.message,text:msg_dtype_category"
+msgid "Categories"
+msgstr "Kategorien"
+
msgctxt "model:ir.message,text:msg_name_graph"
msgid "Graph: %(gname)s"
msgstr "Diagramm: %(gname)s"
diff --git a/locale/en.po b/locale/en.po
index 67ddf0f..0966cbb 100644
--- a/locale/en.po
+++ b/locale/en.po
@@ -7,8 +7,20 @@ msgid "Type of evaluation must be '%(typename)s'."
msgstr "Type of evaluation must be '%(typename)s'."
msgctxt "model:ir.message,text:msg_dtype_cashbook"
-msgid "Cashbooks"
-msgstr "Cashbooks"
+msgid "Cashbooks [Amount]"
+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"
msgid "Types of Cashbooks"
@@ -18,6 +30,10 @@ msgctxt "model:ir.message,text:msg_dtype_currency"
msgid "Currencies"
msgstr "Currencies"
+msgctxt "model:ir.message,text:msg_dtype_category"
+msgid "Categories"
+msgstr "Categories"
+
msgctxt "model:ir.message,text:msg_name_graph"
msgid "Graph: %(gname)s"
msgstr "Graph: %(gname)s"
diff --git a/message.xml b/message.xml
index 2b66901..ec34ead 100644
--- a/message.xml
+++ b/message.xml
@@ -9,7 +9,16 @@ full copyright notices and license terms. -->
Type of evaluation must be '%(typename)s'.
- Cashbooks
+ Cashbooks [Amount]
+
+
+ Cashbooks [Amount of Profit/Loss]
+
+
+ Cashbooks [Percent of Profit/Loss]
+
+
+ Cashbooks [Current Value]
Types of Cashbooks
@@ -17,6 +26,9 @@ full copyright notices and license terms. -->
Currencies
+
+ Categories
+
Graph: %(gname)s
diff --git a/setup.py b/setup.py
index 5b7501b..b1a0cf1 100644
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@ with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
# tryton.cfg einlesen
config = ConfigParser()
-config.readfp(open('tryton.cfg'))
+config.read_file(open('tryton.cfg'))
info = dict(config.items('tryton'))
for key in ('depends', 'extras_depend', 'xml'):
if key in info:
@@ -68,6 +68,7 @@ setup(name='%s_%s' % (PREFIX, MODULE),
description='Tryton module to add reports to cashbook.',
long_description=long_description,
url='https://www.m-ds.de/',
+ download_url='https://scmdev.m-ds.de/Tryton/Extra/cashbook_report',
author='martin-data services',
author_email='service@m-ds.de',
license='GPL-3',
diff --git a/templates.py b/templates.py
index d3432f9..95e3857 100644
--- a/templates.py
+++ b/templates.py
@@ -3,6 +3,7 @@
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
+cashbook_types = ['cashbooks', 'cashbooks_gldiff', 'cashbooks_glperc', 'cashbooks_glvalue']
template_view_line = ''
diff --git a/tests/test_report.py b/tests/test_report.py
index 7d8f2d4..c75cbe2 100644
--- a/tests/test_report.py
+++ b/tests/test_report.py
@@ -510,6 +510,31 @@ class ReportTestCase(CashbookTestCase):
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],
{
@@ -684,6 +709,90 @@ class ReportTestCase(CashbookTestCase):
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')
+
+ 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'),
+ }, ])],
+ }])
+
+ AccType.write(*[
+ [books[0].btype],
+ {
+ 'feature': 'asset',
+ }])
+
+ books = self.prep_report_3books()
+ Book.write(*[
+ books,
+ {
+ 'asset': asset.id,
+ 'quantity_uom': asset.uom.id,
+ 'quantity_digits': 3,
+ }])
+ self.assertEqual(books[0].rec_name, 'ss')
+
+ 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('23.81'))
+ self.assertEqual(evaluation.line_values[1].balance, Decimal('11.90'))
+ self.assertEqual(evaluation.line_values[2].balance, Decimal('23.00'))
+
@with_transaction()
def test_report_chart_pie_book_red(self):
""" create 3x cashbooks, add bookings,
@@ -719,7 +828,7 @@ class ReportTestCase(CashbookTestCase):
-
+
""")
diff --git a/tryton.cfg b/tryton.cfg
index 22b19dd..a53b760 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -4,8 +4,9 @@ depends:
res
cashbook
cashbook_bookcategory
-extras_depend:
+#extras_depend:
dashboard
+ cashbook_investment
xml:
icon.xml
message.xml