extend evaluation for cashbook-profit/loss amount/percent/diff - todo
This commit is contained in:
parent
6ee40e8cff
commit
9774f183ad
11 changed files with 265 additions and 21 deletions
|
@ -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'])
|
||||
|
|
|
@ -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],
|
||||
|
|
67
investment.py
Normal file
67
investment.py
Normal file
|
@ -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
|
14
line.py
14
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
|
||||
|
|
20
locale/de.po
20
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"
|
||||
|
|
20
locale/en.po
20
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"
|
||||
|
|
14
message.xml
14
message.xml
|
@ -9,7 +9,16 @@ full copyright notices and license terms. -->
|
|||
<field name="text">Type of evaluation must be '%(typename)s'.</field>
|
||||
</record>
|
||||
<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 model="ir.message" id="msg_dtype_type">
|
||||
<field name="text">Types of Cashbooks</field>
|
||||
|
@ -17,6 +26,9 @@ full copyright notices and license terms. -->
|
|||
<record model="ir.message" id="msg_dtype_currency">
|
||||
<field name="text">Currencies</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_dtype_category">
|
||||
<field name="text">Categories</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_name_graph">
|
||||
<field name="text">Graph: %(gname)s</field>
|
||||
</record>
|
||||
|
|
3
setup.py
3
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',
|
||||
|
|
|
@ -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 = '<field name="balance" fill="%(fill)s" empty="0" string="%(string)s"/>'
|
||||
|
||||
|
|
|
@ -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):
|
|||
<field name="name"/>
|
||||
</x>
|
||||
<y>
|
||||
<field name="balance" fill="1" empty="0" string="Cashbooks"/>
|
||||
<field name="balance" fill="1" empty="0" string="Cashbooks [Amount]"/>
|
||||
</y>
|
||||
</graph>
|
||||
""")
|
||||
|
|
|
@ -4,8 +4,9 @@ depends:
|
|||
res
|
||||
cashbook
|
||||
cashbook_bookcategory
|
||||
extras_depend:
|
||||
#extras_depend:
|
||||
dashboard
|
||||
cashbook_investment
|
||||
xml:
|
||||
icon.xml
|
||||
message.xml
|
||||
|
|
Loading…
Reference in a new issue