asset: online-quelle als liste

This commit is contained in:
Frederik Jaeckel 2022-11-29 21:54:27 +01:00
parent 8760fd4aab
commit b8495231e5
8 changed files with 171 additions and 100 deletions

View file

@ -4,7 +4,7 @@
# full copyright notices and license terms. # full copyright notices and license terms.
from trytond.pool import Pool from trytond.pool import Pool
from .asset import Asset from .asset import Asset, AssetSourceRel
from .rate import Rate from .rate import Rate
from .identifier import Identifier from .identifier import Identifier
from .cron import Cron from .cron import Cron
@ -16,6 +16,7 @@ from .diagram import GraphDef, ChartPoint
def register(): def register():
Pool.register( Pool.register(
OnlineSource, OnlineSource,
AssetSourceRel,
Asset, Asset,
Rate, Rate,
Identifier, Identifier,

View file

@ -78,15 +78,16 @@ class Asset(ModelSQL, ModelView):
help='Stock market symbol'), help='Stock market symbol'),
'get_identifiers', searcher='search_identifier') 'get_identifiers', searcher='search_identifier')
updtsource = fields.Many2One(string='Update Source', updtsources = fields.Many2Many(string='Update Sources',
help='Select a source for the course update.', help='Select sources for the course update. The course sources are tried until a valid value has been read.',
ondelete='SET NULL', model_name='investment.source') relation_name='investment.asset_source_rel',
origin='asset', target='source')
updtdays = fields.Selection(string='Select days', required=True, updtdays = fields.Selection(string='Select days', required=True,
selection=sel_updtdays) selection=sel_updtdays)
updttime = fields.Time(string='Time', updttime = fields.Time(string='Time',
states={ states={
'readonly': ~Bool(Eval('updtsource')), 'readonly': ~Bool(Eval('updtsources')),
}, depends=['updtsource']) }, depends=['updtsources'])
nextupdate = fields.Function(fields.DateTime(string='Next Update', nextupdate = fields.Function(fields.DateTime(string='Next Update',
readonly=True), readonly=True),
'get_nextupdates', searcher='search_nextupdate') 'get_nextupdates', searcher='search_nextupdate')
@ -113,12 +114,48 @@ class Asset(ModelSQL, ModelView):
readonly=True, digits=(16,digits_percent)), readonly=True, digits=(16,digits_percent)),
'get_percentage_change', searcher='search_percentage') 'get_percentage_change', searcher='search_percentage')
@classmethod
def __register__(cls, module_name):
""" register and migrate
"""
super(Asset, cls).__register__(module_name)
cls.migrate_updtsource(module_name)
@classmethod @classmethod
def __setup__(cls): def __setup__(cls):
super(Asset, cls).__setup__() super(Asset, cls).__setup__()
cls._order.insert(0, ('name', 'ASC')) cls._order.insert(0, ('name', 'ASC'))
cls._order.insert(0, ('date', 'DESC')) cls._order.insert(0, ('date', 'DESC'))
@classmethod
def migrate_updtsource(cls, module_name):
""" replace 'updtsource' by relation
"""
pool = Pool()
Asset2 = pool.get('investment.asset')
asset_table = Asset2.__table_handler__(module_name)
if asset_table.column_exist('updtsource'):
AssetSourceRel = pool.get('investment.asset_source_rel')
tab_asset = Asset2.__table__()
cursor = Transaction().connection.cursor()
query = tab_asset.select(
tab_asset.id,
tab_asset.updtsource,
where = tab_asset.updtsource != None,
)
cursor.execute(*query)
records = cursor.fetchall()
to_create = [{
'asset': x[0],
'source': x[1],
} for x in records]
if len(to_create) > 0:
AssetSourceRel.create(to_create)
asset_table.drop_column('updtsource')
@classmethod @classmethod
def view_attributes(cls): def view_attributes(cls):
return super().view_attributes() + [ return super().view_attributes() + [
@ -164,11 +201,11 @@ class Asset(ModelSQL, ModelView):
""" """
return 'work' return 'work'
@fields.depends('updtsource', 'updttime') @fields.depends('updtsources', 'updttime')
def on_change_updtsource(self): def on_change_updtsources(self):
""" clear time-fields """ clear time-fields
""" """
if self.updtsource is None: if len(self.updtsources) == 0:
self.updttime = None self.updttime = None
else : else :
self.updttime = time(11, 30) self.updttime = time(11, 30)
@ -513,15 +550,21 @@ class Asset(ModelSQL, ModelView):
""" """
pool = Pool() pool = Pool()
Asset = pool.get('investment.asset') Asset = pool.get('investment.asset')
AssetSourceRel = pool.get('investment.asset_source_rel')
Rate = pool.get('investment.rate') Rate = pool.get('investment.rate')
tab_asset = Asset.__table__() tab_asset = Asset.__table__()
tab_rate = Rate.__table__() tab_rate = Rate.__table__()
tab_rel = AssetSourceRel.__table__()
context = Transaction().context context = Transaction().context
query_date = context.get('qdate', CurrentDate() - Literal(1)) query_date = context.get('qdate', CurrentDate() - Literal(1))
# get last date of rate # get last date of rate
tab_date = tab_asset.join(tab_rate, tab_date = tab_asset.join(tab_rel,
# link to asset-source-relation to check if
# there are online-sources set
condition=tab_rel.asset == tab_asset.id,
).join(tab_rate,
condition=tab_asset.id == tab_rate.asset, condition=tab_asset.id == tab_rate.asset,
type_ = 'LEFT OUTER', type_ = 'LEFT OUTER',
).select( ).select(
@ -531,7 +574,6 @@ class Asset(ModelSQL, ModelView):
tab_asset.updttime, tab_asset.updttime,
distinct_on = [tab_asset.id], distinct_on = [tab_asset.id],
order_by = [tab_asset.id, tab_rate.date.desc], order_by = [tab_asset.id, tab_rate.date.desc],
where=tab_asset.updtsource != None,
) )
query = tab_date.select( query = tab_date.select(
@ -768,27 +810,18 @@ class Asset(ModelSQL, ModelView):
]): ]):
OnlineSource.update_rate(asset) OnlineSource.update_rate(asset)
@classmethod
def create(cls, vlist):
""" add debit/credit
"""
vlist = [x.copy() for x in vlist]
for values in vlist:
if 'updtsource' in values.keys():
if values['updtsource'] is None:
values['updttime'] = None
return super(Asset, cls).create(vlist)
@classmethod
def write(cls, *args):
""" deny update if cashbook.line!='open',
add or update debit/credit
"""
actions = iter(args)
for lines, values in zip(actions, actions):
if 'updtsource' in values.keys():
if values['updtsource'] is None:
values['updttime'] = None
super(Asset, cls).write(*args)
# end Asset # end Asset
class AssetSourceRel(ModelSQL):
'Asset Source Relation'
__name__ = 'investment.asset_source_rel'
source = fields.Many2One(string='Online Source', select=True,
required=True, model_name='investment.source',
ondelete='CASCADE')
asset = fields.Many2One(string='Asset', select=True,
required=True, model_name='investment.asset',
ondelete='CASCADE')
# end AssetSourceRel

View file

@ -182,13 +182,13 @@ msgctxt "help:investment.asset,date:"
msgid "Date of current rate" msgid "Date of current rate"
msgstr "Datum des aktuellen Kurses" msgstr "Datum des aktuellen Kurses"
msgctxt "field:investment.asset,updtsource:" msgctxt "field:investment.asset,updtsources:"
msgid "Update Source" msgid "Update Sources"
msgstr "Kursquelle" msgstr "Kursquellen"
msgctxt "help:investment.asset,updtsource:" msgctxt "help:investment.asset,updtsources:"
msgid "Select a source for the course update." msgid "Select sources for the course update. The course sources are tried until a valid value has been read."
msgstr "Wählen Sie eine Quelle für die Kursaktualisierung aus." msgstr "Wählen Sie Quellen für die Kursaktualisierung aus. Die Kursquellen werden probiert bis ein gültiger Wert gelesen wurde."
msgctxt "field:investment.asset,updttime:" msgctxt "field:investment.asset,updttime:"
msgid "Time" msgid "Time"
@ -251,6 +251,22 @@ msgid "Mon - Sun"
msgstr "Mo - So" msgstr "Mo - So"
###############################
# investment.asset-source-rel #
###############################
msgctxt "model:investment.asset_source_rel,name:"
msgid "Asset Source Relation"
msgstr "Vermögenswert Quelle Verknüpfung"
msgctxt "field:investment.asset_source_rel,source:"
msgid "Source"
msgstr "Quelle"
msgctxt "field:investment.asset_source_rel,asset:"
msgid "Asset"
msgstr "Vermögenswert"
##################### #####################
# investment.source # # investment.source #
##################### #####################

View file

@ -154,13 +154,13 @@ msgctxt "help:investment.asset,date:"
msgid "Date of current rate" msgid "Date of current rate"
msgstr "Date of current rate" msgstr "Date of current rate"
msgctxt "field:investment.asset,updtsource:" msgctxt "field:investment.asset,updtsources:"
msgid "Update Source" msgid "Update Sources"
msgstr "Update Source" msgstr "Update Sources"
msgctxt "help:investment.asset,updtsource:" msgctxt "help:investment.asset,updtsources:"
msgid "Select a source for the course update." msgid "Select sources for the course update. The course sources are tried until a valid value has been read."
msgstr "Select a source for the course update." msgstr "Select sources for the course update. The course sources are tried until a valid value has been read."
msgctxt "field:investment.asset,updttime:" msgctxt "field:investment.asset,updttime:"
msgid "Time" msgid "Time"
@ -222,6 +222,18 @@ msgctxt "selection:investment.asset,updtdays:"
msgid "Mon - Sun" msgid "Mon - Sun"
msgstr "Mon - Sun" msgstr "Mon - Sun"
msgctxt "model:investment.asset_source_rel,name:"
msgid "Asset Source Relation"
msgstr "Asset Source Relation"
msgctxt "field:investment.asset_source_rel,source:"
msgid "Source"
msgstr "Source"
msgctxt "field:investment.asset_source_rel,asset:"
msgid "Asset"
msgstr "Asset"
msgctxt "model:investment.source,name:" msgctxt "model:investment.source,name:"
msgid "Online Source" msgid "Online Source"
msgstr "Online Source" msgstr "Online Source"

View file

@ -222,48 +222,56 @@ class OnlineSource(ModelSQL, ModelView):
""" """
pool = Pool() pool = Pool()
Rate = pool.get('investment.rate') Rate = pool.get('investment.rate')
IrDate = pool.get('ir.date')
if asset.updtsource is None: if len(asset.updtsources) == 0:
return return
rate_data = cls.read_from_website(
asset.updtsource,
isin = asset.isin,
nsin = asset.wkn,
symbol = asset.secsymb,
)
if len(asset.updtsource.rgxident or '') > 0: for updtsource in asset.updtsources:
# check result - same code? rate_data = cls.read_from_website(
code = rate_data.get('code', None) updtsource,
if code: isin = asset.isin,
asset_code = getattr(asset, { nsin = asset.wkn,
'isin': 'isin', symbol = asset.secsymb,
'nsin': 'wkn', )
'symbol': 'secsymb',
}[asset.updtsource.rgxidtype])
if (asset_code or '').lower() != code.lower():
# fail
logger.warning(
'update_rate: got wrong code "%(wrong)s" - expected "%(exp)s"' % {
'exp': asset_code,
'wrong': code,
})
return False
to_create = { if len(updtsource.rgxident or '') > 0:
'date': rate_data.get('date', None), # check result - same code?
'rate': rate_data.get('rate', None), code = rate_data.get('code', None)
'asset': asset.id, if code:
} asset_code = getattr(asset, {
if (to_create['date'] is not None) and \ 'isin': 'isin',
(to_create['rate'] is not None): 'nsin': 'wkn',
# check if exists 'symbol': 'secsymb',
if Rate.search_count([ }[updtsource.rgxidtype])
('asset.id', '=', asset.id), if (asset_code or '').lower() != code.lower():
('date', '=', to_create['date']), # fail
]) == 0: logger.warning(
Rate.create([to_create]) 'update_rate: got wrong code "%(wrong)s" - expected "%(exp)s"' % {
return True 'exp': asset_code,
'wrong': code,
})
continue
to_create = {
'date': rate_data.get('date', None),
'rate': rate_data.get('rate', None),
'asset': asset.id,
}
if (to_create['date'] is not None) and \
(to_create['rate'] is not None):
# check if exists
if Rate.search_count([
('asset.id', '=', asset.id),
('date', '=', to_create['date']),
]) == 0:
Rate.create([to_create])
return True
else :
# if we got a record for today - stop
# otherwise try next source
if to_create['date'] == IrDate.today():
break
return False return False
def get_regex_result(self, html_text, field_name): def get_regex_result(self, html_text, field_name):

View file

@ -568,18 +568,19 @@ class AssetTestCase(ModuleTestCase):
'name': 'Source 1', 'name': 'Source 1',
}]) }])
self.assertEqual(asset.updtsource, None) self.assertEqual(len(asset.updtsources), 0)
self.assertEqual(asset.updttime, time(14,0)) self.assertEqual(asset.updttime, time(14,0))
asset.updtsource = o_source asset.updtsources = [o_source]
asset.updttime = time(10, 45) asset.updttime = time(10, 45)
asset.save() asset.save()
self.assertEqual(asset.updtsource.rec_name, 'Source 1') self.assertEqual(len(asset.updtsources), 1)
self.assertEqual(asset.updtsources[0].rec_name, 'Source 1')
self.assertEqual(asset.updttime, time(10, 45)) self.assertEqual(asset.updttime, time(10, 45))
asset.updtsource = None asset.updtsources = []
asset.on_change_updtsource() asset.on_change_updtsources()
self.assertEqual(asset.updtsource, None) self.assertEqual(len(asset.updtsources), 0)
self.assertEqual(asset.updttime, None) self.assertEqual(asset.updttime, None)
@with_transaction() @with_transaction()
@ -606,7 +607,7 @@ class AssetTestCase(ModuleTestCase):
Asset.write(*[ Asset.write(*[
[asset], [asset],
{ {
'updtsource': o_source.id, 'updtsources': [('add', [o_source.id])],
'updttime': time(10, 45), 'updttime': time(10, 45),
}]) }])
@ -616,7 +617,8 @@ class AssetTestCase(ModuleTestCase):
# re-read to make context work # re-read to make context work
asset2, = Asset.browse([asset.id]) asset2, = Asset.browse([asset.id])
self.assertEqual(asset2.updtsource.rec_name, 'Source 1') self.assertEqual(len(asset2.updtsources), 1)
self.assertEqual(asset2.updtsources[0].rec_name, 'Source 1')
self.assertEqual(asset2.updttime, time(10, 45)) self.assertEqual(asset2.updttime, time(10, 45))
self.assertEqual(len(asset2.rates), 0) self.assertEqual(len(asset2.rates), 0)
# qdate = 2022-10-14 simulates existence of record at this day # qdate = 2022-10-14 simulates existence of record at this day
@ -643,7 +645,7 @@ class AssetTestCase(ModuleTestCase):
self.assertEqual(len(asset.rates), 1) self.assertEqual(len(asset.rates), 1)
asset2, = Asset.browse([asset.id]) asset2, = Asset.browse([asset.id])
self.assertEqual(asset.updtsource.rec_name, 'Source 1') self.assertEqual(asset.updtsources[0].rec_name, 'Source 1')
self.assertEqual(asset.updttime, time(10, 45)) self.assertEqual(asset.updttime, time(10, 45))
self.assertEqual(len(asset.rates), 1) self.assertEqual(len(asset.rates), 1)
self.assertEqual(asset.rates[0].date, date(2022, 10, 17)) self.assertEqual(asset.rates[0].date, date(2022, 10, 17))
@ -668,7 +670,7 @@ class AssetTestCase(ModuleTestCase):
self.assertEqual(len(asset.rates), 2) self.assertEqual(len(asset.rates), 2)
asset2, = Asset.browse([asset.id]) asset2, = Asset.browse([asset.id])
self.assertEqual(asset2.updtsource.rec_name, 'Source 1') self.assertEqual(asset2.updtsources[0].rec_name, 'Source 1')
self.assertEqual(asset2.updttime, time(10, 45)) self.assertEqual(asset2.updttime, time(10, 45))
self.assertEqual(len(asset2.rates), 2) self.assertEqual(len(asset2.rates), 2)
self.assertEqual(asset2.rates[0].date, date(2022, 10, 18)) self.assertEqual(asset2.rates[0].date, date(2022, 10, 18))

View file

@ -64,7 +64,7 @@ class SourceTestCase(ModuleTestCase):
Asset.write(*[ Asset.write(*[
[asset], [asset],
{ {
'updtsource': osource.id, 'updtsources': [('add', [osource.id])],
}]) }])
with Transaction().set_context({ with Transaction().set_context({
@ -76,7 +76,8 @@ class SourceTestCase(ModuleTestCase):
self.assertEqual(asset2.isin, 'XC0009655157') self.assertEqual(asset2.isin, 'XC0009655157')
self.assertEqual(asset2.secsymb, '1472977') self.assertEqual(asset2.secsymb, '1472977')
self.assertEqual(asset2.updttime, time(14, 0)) self.assertEqual(asset2.updttime, time(14, 0))
self.assertEqual(asset2.updtsource.rec_name, 'Source 1') self.assertEqual(len(asset2.updtsources), 1)
self.assertEqual(asset2.updtsources[0].rec_name, 'Source 1')
self.assertEqual(asset2.updtdays, 'work') self.assertEqual(asset2.updtdays, 'work')
self.assertEqual(asset2.nextupdate, datetime(2022, 10, 3, 14, 0)) self.assertEqual(asset2.nextupdate, datetime(2022, 10, 3, 14, 0))
self.assertEqual(len(asset.rates), 0) self.assertEqual(len(asset.rates), 0)

View file

@ -57,14 +57,12 @@ full copyright notices and license terms. -->
<field name="rates" mode="tree,form,graph"/> <field name="rates" mode="tree,form,graph"/>
</page> </page>
<page id="pgupdate" col="4" string="Course Update"> <page id="pgupdate" col="4" string="Course Update">
<label name="updtsource"/>
<field name="updtsource"/>
<label name="updttime"/> <label name="updttime"/>
<field name="updttime"/> <field name="updttime"/>
<label id="labupdt" colspan="2" string=" "/>
<label name="updtdays"/> <label name="updtdays"/>
<field name="updtdays"/> <field name="updtdays"/>
<field name="updtsources" colspan="4"/>
</page> </page>
</notebook> </notebook>