asset: abfragezeit für prozente optimiert

This commit is contained in:
Frederik Jaeckel 2023-01-07 16:26:22 +01:00
parent 3dc79fc292
commit 8cfa54f693
22 changed files with 114 additions and 242 deletions

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.

174
asset.py
View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
@ -11,7 +11,7 @@ from trytond.report import Report
from decimal import Decimal
from datetime import time
from sql.functions import CurrentDate, CurrentTimestamp, Round, Extract
from sql.conditionals import Case, Coalesce
from sql.conditionals import Case, Coalesce, NullIf
from sql import Literal
from .diagram import Concat2
@ -116,7 +116,7 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
'get_percentage_change', searcher='search_percentage')
change_symbol = fields.Function(fields.Many2One(string='Symbol',
readonly=True, model_name='investment.rate'),
'get_percentage_change')
'get_rate_data')
@classmethod
def __register__(cls, module_name):
@ -317,6 +317,7 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
tab_asset.id,
Round(tab_rate.rate, tab_asset.currency_digits).as_('rate'),
tab_rate.date,
tab_rate.id.as_('id_rate'),
distinct_on=[tab_asset.id],
order_by=[tab_asset.id, tab_rate.date.desc],
)
@ -338,12 +339,16 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
result = {x:{y.id: None for y in assets} for x in names}
for record in records:
(id1, rate1, date1) = record
(id1, rate1, date1, id_rate) = record
asset = Asset2(id1)
exp = Decimal(Decimal(1) / 10 ** (asset.currency_digits or 4))
values = {'rate': record[1].quantize(exp), 'date': record[2]}
values = {
'rate': record[1].quantize(exp),
'date': record[2],
'change_symbol': id_rate,
}
for name in names:
result[name][record[0]] = values[name]
@ -403,78 +408,48 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
return [query]
@classmethod
def get_percentage_sql(cls, name_lst, select_date=True):
def get_percentage_sql(cls, days=0, asset_ids=None):
""" get table for percentages and dates,
generate adapted query
select_date: True = select newest date
days: delta-days to past to select percent-value
0=yesterday, 30=last month, ...
"""
pool = Pool()
Rate = pool.get('investment.rate')
Asset = pool.get('investment.asset')
tab_asset = Asset.__table__()
tab_rate_today = Rate.__table__()
rate_tab = {
'day1': {'tab': Rate.__table__(), 'day': 0},
'month1': {'tab': Rate.__table__(), 'day': 30},
'month3': {'tab': Rate.__table__(), 'day': 3*30},
'month6': {'tab': Rate.__table__(), 'day': 6*30},
'month12': {'tab': Rate.__table__(), 'day': 12*30},
}
Asset2 = pool.get('investment.asset')
tab_asset = Asset2.__table__()
tab_rate1 = Rate.__table__()
tab_rate2 = Rate.__table__()
context = Transaction().context
# create tables to query percentual changes for
# 1 day, 30 days, 3 months, 6 months, 1 year
query_date = context.get('qdate', CurrentDate())
query_today = tab_asset.join(tab_rate_today,
condition=tab_asset.id==tab_rate_today.asset,
where_asset = tab_rate1.date <= query_date
if isinstance(asset_ids, list):
where_asset &= tab_asset.id.in_(asset_ids)
tab_today = tab_asset.join(tab_rate1,
condition=tab_asset.id==tab_rate1.asset,
).select(
tab_asset.id,
tab_rate_today.id.as_('id_rate'),
tab_rate_today.date,
tab_rate_today.rate,
tab_rate1.date,
tab_rate1.rate,
distinct_on=[tab_asset.id],
order_by=[tab_asset.id, tab_rate1.date.desc],
where=where_asset,
)
# 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:
query = query.join(rate_tab[name]['tab'],
# select newest date from <period> until 5 days older
condition=(query_today.id==rate_tab[name]['tab'].asset) & \
(query_today.date > (rate_tab[name]['tab'].date + Literal(rate_tab[name]['day']))) & \
(query_today.date <= (rate_tab[name]['tab'].date + Literal(rate_tab[name]['day'] + 5))),
type_ = 'LEFT OUTER')
# add select for requested fields to join
select_lst = [
query_today.id,
query_today.id_rate,
query_today.date,
]
for name in name_lst:
select_lst.append(
Case(
((rate_tab[name]['tab'].rate != None) & (query_today.rate != None) & \
(rate_tab[name]['tab'].rate != Literal(0.0)),
query_today.rate * Literal(100.0) / rate_tab[name]['tab'].rate - Literal(100.0)),
else_ = None,
).as_(name))
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, query_today.id_rate],
order_by=order_by_lst,
days_diff = days + 5
query = tab_today.join(tab_rate2,
condition=(tab_today.id==tab_rate2.asset) & \
(tab_today.date > (tab_rate2.date + days)) & \
(tab_today.date <= (tab_rate2.date + days_diff)),
type_ = 'LEFT OUTER',
).select(
tab_today.id,
tab_today.date,
tab_today.rate,
(tab_today.rate * 100.0 / NullIf(tab_rate2.rate, 0.00) - 100.0).as_('percent'),
distinct_on=[tab_today.id],
order_by=[tab_today.id, tab_today.date.desc]
)
return query
@ -483,11 +458,11 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
""" order day1
"""
Assert = Pool().get('investment.asset')
tab_asset = Asset.get_percentage_sql(['day1'])
tab_asset = Asset.get_percentage_sql(days=0)
table, _ = tables[None]
query = tab_asset.select(
tab_asset.day1,
tab_asset.percent,
where=tab_asset.id==table.id,
)
return [query]
@ -497,11 +472,11 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
""" order month1
"""
Assert = Pool().get('investment.asset')
tab_asset = Asset.get_percentage_sql(['month1'])
tab_asset = Asset.get_percentage_sql(days=30)
table, _ = tables[None]
query = tab_asset.select(
tab_asset.month1,
tab_asset.percent,
where=tab_asset.id==table.id,
)
return [query]
@ -511,11 +486,11 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
""" order month1
"""
Assert = Pool().get('investment.asset')
tab_asset = Asset.get_percentage_sql(['month3'])
tab_asset = Asset.get_percentage_sql(days=90)
table, _ = tables[None]
query = tab_asset.select(
tab_asset.month3,
tab_asset.percent,
where=tab_asset.id==table.id,
)
return [query]
@ -525,11 +500,11 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
""" order month1
"""
Assert = Pool().get('investment.asset')
tab_asset = Asset.get_percentage_sql(['month6'])
tab_asset = Asset.get_percentage_sql(days=180)
table, _ = tables[None]
query = tab_asset.select(
tab_asset.month6,
tab_asset.percent,
where=tab_asset.id==table.id,
)
return [query]
@ -539,11 +514,11 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
""" order month1
"""
Assert = Pool().get('investment.asset')
tab_asset = Asset.get_percentage_sql(['month12'])
tab_asset = Asset.get_percentage_sql(days=365)
table, _ = tables[None]
query = tab_asset.select(
tab_asset.month12,
tab_asset.percent,
where=tab_asset.id==table.id,
)
return [query]
@ -554,10 +529,16 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
"""
Operator = fields.SQL_OPERATORS[clause[1]]
field_name = clause[0][len('change_'):]
tab_percent = cls.get_percentage_sql([field_name])
tab_percent = cls.get_percentage_sql(days={
'day1': 0,
'month1': 30,
'month3': 90,
'month6': 180,
'month12': 365,
}[field_name])
query = tab_percent.select(tab_percent.id,
where=Operator(Round(getattr(tab_percent, field_name), 2),
where=Operator(Round(tab_percent.percent, 2),
clause[2]))
return [('id', 'in', query)]
@ -567,29 +548,26 @@ class Asset(SymbolMixin, ModelSQL, ModelView):
"""
cursor = Transaction().connection.cursor()
name_lst = [x[len('change_'):] for x in names
if x != 'change_symbol']
tab_percent = cls.get_percentage_sql(name_lst)
query = tab_percent.select(
tab_percent.id,
tab_percent.id_rate,
*[getattr(tab_percent, x) for x in name_lst],
where=tab_percent.id.in_([x.id for x in assets]),
)
cursor.execute(*query)
records = cursor.fetchall()
result = {x:{y.id: None for y in assets} for x in names}
exp = Decimal(Decimal(1) / 10 ** digits_percent)
for record in records:
if 'change_symbol' in names:
result['change_symbol'][record[0]] = record[1]
cnt1 = 2
for x in name_lst:
result['change_%s' % x][record[0]] = record[cnt1].quantize(exp) \
if record[cnt1] is not None else None
cnt1 += 1
for x in names:
tab_percent = cls.get_percentage_sql(
days={
'change_day1': 0,
'change_month1': 30,
'change_month3': 90,
'change_month6': 180,
'change_month12': 365,
}[x],
asset_ids=[x.id for x in assets]
)
cursor.execute(*tab_percent)
records = cursor.fetchall()
for record in records:
result[x][record[0]] = record[3].quantize(exp) \
if record[3] is not None else None
return result
@classmethod

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the cashbook-module from m-ds for Tryton.
<!-- This file is part of the cashbook-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>

View file

@ -250,13 +250,15 @@ class AssetTestCase(ModuleTestCase):
self.assertEqual(asset1.rates[3].date, date(2022, 5, 3))
# query fixed date
tab_percent = Asset.get_percentage_sql(['day1'], select_date = False)
tab_percent = Asset.get_percentage_sql(days=0)
with Transaction().set_context({
'qdate': date(2022, 5, 16),
}):
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),
tab_percent.percent,
where=tab_percent.id==asset1.id,
)
cursor.execute(*query)
records = cursor.fetchall()
@ -268,114 +270,6 @@ class AssetTestCase(ModuleTestCase):
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/u | 05/16/2022')
self.assertEqual(len(asset1.rates), 4)
self.assertEqual(asset2.rec_name, 'Product 1 | 1.5000 usd/u | 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

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds for Tryton.
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!-- This file is part of the investment-module from m-ds for Tryton.
<!-- This file is part of the investment-module from m-ds.de for Tryton.
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tryton>