diff --git a/__init__.py b/__init__.py
index 161c360..ff6b8fc 100644
--- a/__init__.py
+++ b/__init__.py
@@ -10,6 +10,7 @@ from .identifier import Identifier
from .cron import Cron
from .onlinesource import OnlineSource
from .update_wiz import UpdateSoureWizard
+from .diagram import GraphDef, ChartPoint
def register():
@@ -20,6 +21,10 @@ def register():
Identifier,
Cron,
module='investment', type_='model')
+ Pool.register(
+ GraphDef,
+ ChartPoint,
+ module='investment', type_='model', depends=['diagram'])
Pool.register(
UpdateSoureWizard,
module='investment', type_='wizard')
diff --git a/asset.py b/asset.py
index 66869f9..8ce8bad 100644
--- a/asset.py
+++ b/asset.py
@@ -244,9 +244,10 @@ class Asset(ModelSQL, ModelView):
return self.company.currency.id
@classmethod
- def get_percentage_sql(cls, name_lst):
+ def get_percentage_sql(cls, name_lst, select_date=True):
""" get table for percentages and dates,
generate adapted query
+ select_date: True = select newest date
"""
pool = Pool()
Rate = pool.get('investment.rate')
@@ -270,13 +271,17 @@ class Asset(ModelSQL, ModelView):
condition=tab_asset.id==tab_rate_today.asset,
).select(
tab_asset.id,
+ tab_rate_today.id.as_('id_rate'),
tab_rate_today.date,
tab_rate_today.rate,
- distinct_on=[tab_asset.id],
- order_by=[tab_asset.id, tab_rate_today.date.desc],
- where=tab_rate_today.date <= query_date,
)
+ # limit to newest date until 'query_date'
+ if select_date == True:
+ query_today.distinct_on=[tab_asset.id]
+ query_today.order_by=[tab_asset.id, tab_rate_today.date.desc]
+ query_today.where=tab_rate_today.date <= query_date
+
# create join for requested fields, to minimize database-load
query = query_today
for name in name_lst:
@@ -290,6 +295,7 @@ class Asset(ModelSQL, ModelView):
# add select for requested fields to join
select_lst = [
query_today.id,
+ query_today.id_rate,
query_today.date,
]
for name in name_lst:
@@ -301,14 +307,14 @@ class Asset(ModelSQL, ModelView):
else_ = None,
).as_(name))
- order_by_lst = [query_today.id]
+ order_by_lst = [query_today.id, query_today.id_rate]
order_by_lst.extend([
rate_tab[name]['tab'].date.desc for name in name_lst
])
query = query.select(
*select_lst,
- distinct_on=[query_today.id],
+ distinct_on=[query_today.id, query_today.id_rate],
order_by=order_by_lst,
)
return query
diff --git a/diagram.py b/diagram.py
new file mode 100644
index 0000000..cfb2c37
--- /dev/null
+++ b/diagram.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+# This file is part of the investment-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.model import ModelView, ModelSQL, fields
+from trytond.transaction import Transaction
+from trytond.pool import Pool, PoolMeta
+from trytond.pyson import Eval
+from sql.functions import Function
+from datetime import timedelta
+from decimal import Decimal
+
+
+class Concat2(Function):
+ """ concat columns
+ """
+ __slots__ = ()
+ _function = 'concat'
+
+# end Concat2
+
+
+class GraphDef(metaclass=PoolMeta):
+ __name__ = 'diagram.graphdef'
+
+ asset = fields.Many2One(string='Asset',
+ model_name='investment.asset',
+ states={
+ 'invisible': Eval('dtype', '') != 'investment.asset',
+ 'required': Eval('dtype', '') == 'investment.asset',
+ }, depends=['dtype'])
+
+ @classmethod
+ def _get_dtypes(cls):
+ """ return list of types
+ """
+ l1 = super(GraphDef, cls)._get_dtypes()
+ l1.append('investment.asset')
+ return l1
+
+ def get_recname_value(self):
+ """ value by dtype
+ """
+ if self.dtype == 'investment.asset':
+ return getattr(self.asset, 'rec_name', '-')
+ return super(GraphDef, self).get_recname_value()
+
+ def get_field_key(self):
+ """ get to read value from json
+ """
+ if self.dtype == 'investment.asset':
+ return 'asset%d' % self.asset.id
+ return super(GraphDef, self).get_field_key()
+
+ def get_scaling_for_investment_asset(self):
+ """ get scaling for currency
+ """
+ Rate = Pool().get('investment.rate')
+
+ if self.scaling == 'fix':
+ return None
+
+ if self.scaling == 'alldata':
+ query = [('asset.id', '=', self.asset.id)]
+ elif self.scaling == 'view':
+ query = [
+ ('asset.id', '=', self.asset.id),
+ ('date', '>=', self.chart.used_start_date()),
+ ('date', '<=', self.chart.used_end_date()),
+ ]
+ elif self.scaling == 'six':
+ query = [
+ ('asset.id', '=', self.asset.id),
+ ('date', '>=', self.chart.used_start_date() - timedelta(days=180)),
+ ('date', '<=', self.chart.used_end_date()),
+ ]
+
+ min_rec = Rate.search(query, limit=1, order=[('rate', 'ASC')])
+ max_rec = Rate.search(query, limit=1, order=[('rate', 'DESC')])
+ min_val = min_rec[0].rate if len(min_rec) > 0 else None
+ max_val = max_rec[0].rate if len(max_rec) > 0 else None
+
+ return self.compute_scaling_factor(min_val, max_val)
+
+# end GraphDef
+
+
+class ChartPoint(metaclass=PoolMeta):
+ __name__ = 'diagram.point'
+
+ @classmethod
+ def get_table_parts(cls):
+ """ return a list of tables to union,
+ table must contain the columns:
+ date, key, val
+ """
+ pool = Pool()
+ Rate = pool.get('investment.rate')
+ tab_rate = Rate.__table__()
+
+ tabparts = super(ChartPoint, cls).get_table_parts()
+
+ # rate
+ tabparts.append(tab_rate.select(
+ tab_rate.date,
+ Concat2('asset', tab_rate.asset).as_('key'),
+ tab_rate.rate.as_('val'),
+ ))
+ return tabparts
+
+# end ChartPoint
diff --git a/diagram.xml b/diagram.xml
new file mode 100644
index 0000000..688d6aa
--- /dev/null
+++ b/diagram.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ diagram.graphdef
+
+ graph_form
+
+
+
+
diff --git a/locale/de.po b/locale/de.po
index c8efa64..4498178 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -449,3 +449,15 @@ msgstr "Wertpapierkennnummer (WKN)"
msgctxt "selection:product.identifier,type:"
msgid "Stock market symbol"
msgstr "Börsensymbol"
+
+
+####################
+# diagram.graphdef #
+####################
+msgctxt "view:diagram.graphdef:"
+msgid "Asset"
+msgstr "Vermögenswert"
+
+msgctxt "field:diagram.graphdef,asset:"
+msgid "Asset"
+msgstr "Vermögenswert"
diff --git a/locale/en.po b/locale/en.po
index 7c1ef65..3b4a074 100644
--- a/locale/en.po
+++ b/locale/en.po
@@ -406,3 +406,11 @@ msgctxt "selection:product.identifier,type:"
msgid "National Securities Identifying Number (NSIN)"
msgstr "National Securities Identifying Number (NSIN)"
+msgctxt "selection:product.identifier,type:"
+msgid "Stock market symbol"
+msgstr "Stock market symbol"
+
+msgctxt "view:diagram.graphdef:"
+msgid "Asset"
+msgstr "Asset"
+
diff --git a/tests/test_asset.py b/tests/test_asset.py
index 2e117ca..a6ad279 100644
--- a/tests/test_asset.py
+++ b/tests/test_asset.py
@@ -112,6 +112,176 @@ class AssetTestCase(ModuleTestCase):
self.assertEqual(asset.rec_name, 'Product 1 - 2.4500 usd/Unit [05/15/2022]')
self.assertEqual(Asset.search_count([('name', '=', 'Product 1')]), 1)
+ @with_transaction()
+ def test_asset_percentages_dateselect1(self):
+ """ create asset, add rates, check selection of
+ specific date - fixed date
+ """
+ Asset = Pool().get('investment.asset')
+ cursor = Transaction().connection.cursor()
+
+ company = self.prep_asset_company()
+ product = self.prep_asset_product(
+ name='Product 1',
+ description='some asset')
+
+ asset1 = self.prep_asset_item(
+ company=company,
+ product = product)
+ self.assertEqual(asset1.rec_name, 'Product 1 - - usd/Unit [-]')
+
+ Asset.write(*[
+ [asset1],
+ {
+ 'rates': [('create', [{
+ 'date': date(2022, 5, 15),
+ 'rate': Decimal('2.45'),
+ }, {
+ 'date': date(2022, 5, 16),
+ 'rate': Decimal('2.6'),
+ }, {
+ 'date': date(2022, 5, 12),
+ 'rate': Decimal('2.0'),
+ }, {
+ 'date': date(2022, 5, 3),
+ 'rate': Decimal('3.6'),
+ }])],
+ },
+ ])
+ self.assertEqual(asset1.rec_name, 'Product 1 - 2.6000 usd/Unit [05/16/2022]')
+ self.assertEqual(len(asset1.rates), 4)
+ self.assertEqual(asset1.rates[0].date, date(2022, 5, 16))
+ self.assertEqual(asset1.rates[1].date, date(2022, 5, 15))
+ self.assertEqual(asset1.rates[2].date, date(2022, 5, 12))
+ self.assertEqual(asset1.rates[3].date, date(2022, 5, 3))
+
+ # query fixed date
+ tab_percent = Asset.get_percentage_sql(['day1'], select_date = False)
+ query = tab_percent.select(
+ tab_percent.id,
+ tab_percent.date,
+ tab_percent.day1,
+ where=(tab_percent.date==date(2022, 5, 16)) & \
+ (tab_percent.id==asset1.id),
+ )
+ cursor.execute(*query)
+ records = cursor.fetchall()
+
+ # there should be one record, three colums
+ self.assertEqual(len(records), 1)
+ self.assertEqual(len(records[0]), 3)
+ self.assertEqual(records[0][0], asset1.id)
+ self.assertEqual(records[0][1], date(2022, 5, 16))
+ self.assertEqual(records[0][2].quantize(Decimal('0.01')), Decimal('6.12'))
+
+ @with_transaction()
+ def test_asset_percentages_dateselect2(self):
+ """ create asset, add rates, check selection of
+ specific date - date-column
+ """
+ pool = Pool()
+ Asset = pool.get('investment.asset')
+ Rate = pool.get('investment.rate')
+ tab_rate = Rate.__table__()
+ cursor = Transaction().connection.cursor()
+
+ company = self.prep_asset_company()
+ product = self.prep_asset_product(
+ name='Product 1',
+ description='some asset')
+
+ asset1 = self.prep_asset_item(
+ company=company,
+ product = product)
+ asset2 = self.prep_asset_item(
+ company=company,
+ product = product)
+
+ Asset.write(*[
+ [asset1],
+ {
+ 'rates': [('create', [{
+ 'date': date(2022, 5, 15),
+ 'rate': Decimal('2.45'),
+ }, {
+ 'date': date(2022, 5, 16),
+ 'rate': Decimal('2.6'),
+ }, {
+ 'date': date(2022, 5, 12),
+ 'rate': Decimal('2.0'),
+ }, {
+ 'date': date(2022, 5, 3),
+ 'rate': Decimal('3.6'),
+ }])],
+ },
+ [asset2],
+ {
+ 'rates': [('create', [{
+ 'date': date(2022, 5, 17),
+ 'rate': Decimal('1.5'),
+ }, {
+ 'date': date(2022, 5, 16),
+ 'rate': Decimal('2.0'),
+ }, {
+ 'date': date(2022, 5, 15),
+ 'rate': Decimal('2.5'),
+ }, {
+ 'date': date(2022, 5, 14),
+ 'rate': Decimal('3.0'),
+ }, {
+ 'date': date(2022, 5, 13),
+ 'rate': Decimal('3.5'),
+ }, {
+ 'date': date(2022, 5, 12),
+ 'rate': Decimal('4.0'),
+ }, {
+ 'date': date(2022, 5, 11),
+ 'rate': Decimal('4.5'),
+ }, ])],
+ },
+ ])
+ self.assertEqual(asset1.rec_name, 'Product 1 - 2.6000 usd/Unit [05/16/2022]')
+ self.assertEqual(len(asset1.rates), 4)
+ self.assertEqual(asset2.rec_name, 'Product 1 - 1.5000 usd/Unit [05/17/2022]')
+ self.assertEqual(len(asset2.rates), 7)
+ self.assertEqual(asset1.rates[0].date, date(2022, 5, 16))
+ self.assertEqual(asset1.rates[1].date, date(2022, 5, 15))
+ self.assertEqual(asset1.rates[2].date, date(2022, 5, 12))
+ self.assertEqual(asset1.rates[3].date, date(2022, 5, 3))
+
+ # query date-column
+ tab_percent = Asset.get_percentage_sql(['day1'], select_date = False)
+ query = tab_rate.join(tab_percent,
+ condition=(tab_percent.id_rate == tab_rate.id)
+ ).select(
+ tab_percent.id,
+ tab_percent.date,
+ tab_percent.day1,
+ where=tab_percent.id==asset1.id,
+ order_by=[tab_percent.date.asc]
+ )
+ cursor.execute(*query)
+ records = cursor.fetchall()
+
+ # there should be 4x records, three colums
+ self.assertEqual(len(records), 4)
+ self.assertEqual(len(records[0]), 3)
+ self.assertEqual(records[0][0], asset1.id)
+ self.assertEqual(records[0][1], date(2022, 5, 3))
+ self.assertEqual(records[0][2], None)
+
+ self.assertEqual(records[1][0], asset1.id)
+ self.assertEqual(records[1][1], date(2022, 5, 12))
+ self.assertEqual(records[1][2], None)
+
+ self.assertEqual(records[2][0], asset1.id)
+ self.assertEqual(records[2][1], date(2022, 5, 15))
+ self.assertEqual(records[2][2].quantize(Decimal('0.01')), Decimal('22.5'))
+
+ self.assertEqual(records[3][0], asset1.id)
+ self.assertEqual(records[3][1], date(2022, 5, 16))
+ self.assertEqual(records[3][2].quantize(Decimal('0.01')), Decimal('6.12'))
+
@with_transaction()
def test_asset_percentages_daterange(self):
""" create asset, add rates, check selection of
diff --git a/tryton.cfg b/tryton.cfg
index cc07bb9..3d0d648 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -6,6 +6,8 @@ depends:
company
currency
product
+extras_depends:
+ diagram
xml:
icon.xml
message.xml
@@ -15,5 +17,6 @@ xml:
sources_def.xml
update_wiz.xml
rate.xml
+ diagram.xml
menu.xml
cron.xml
diff --git a/view/graph_form.xml b/view/graph_form.xml
new file mode 100644
index 0000000..8b4c00f
--- /dev/null
+++ b/view/graph_form.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+