diff --git a/__init__.py b/__init__.py
index ff6b8fc..852ae23 100644
--- a/__init__.py
+++ b/__init__.py
@@ -4,7 +4,7 @@
# full copyright notices and license terms.
from trytond.pool import Pool
-from .asset import Asset
+from .asset import Asset, AssetSourceRel
from .rate import Rate
from .identifier import Identifier
from .cron import Cron
@@ -16,6 +16,7 @@ from .diagram import GraphDef, ChartPoint
def register():
Pool.register(
OnlineSource,
+ AssetSourceRel,
Asset,
Rate,
Identifier,
diff --git a/asset.py b/asset.py
index c4ffab5..9c40c3d 100644
--- a/asset.py
+++ b/asset.py
@@ -78,15 +78,16 @@ class Asset(ModelSQL, ModelView):
help='Stock market symbol'),
'get_identifiers', searcher='search_identifier')
- updtsource = fields.Many2One(string='Update Source',
- help='Select a source for the course update.',
- ondelete='SET NULL', model_name='investment.source')
+ updtsources = fields.Many2Many(string='Update Sources',
+ help='Select sources for the course update. The course sources are tried until a valid value has been read.',
+ relation_name='investment.asset_source_rel',
+ origin='asset', target='source')
updtdays = fields.Selection(string='Select days', required=True,
selection=sel_updtdays)
updttime = fields.Time(string='Time',
states={
- 'readonly': ~Bool(Eval('updtsource')),
- }, depends=['updtsource'])
+ 'readonly': ~Bool(Eval('updtsources')),
+ }, depends=['updtsources'])
nextupdate = fields.Function(fields.DateTime(string='Next Update',
readonly=True),
'get_nextupdates', searcher='search_nextupdate')
@@ -113,12 +114,48 @@ class Asset(ModelSQL, ModelView):
readonly=True, digits=(16,digits_percent)),
'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
def __setup__(cls):
super(Asset, cls).__setup__()
cls._order.insert(0, ('name', 'ASC'))
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
def view_attributes(cls):
return super().view_attributes() + [
@@ -164,11 +201,11 @@ class Asset(ModelSQL, ModelView):
"""
return 'work'
- @fields.depends('updtsource', 'updttime')
- def on_change_updtsource(self):
+ @fields.depends('updtsources', 'updttime')
+ def on_change_updtsources(self):
""" clear time-fields
"""
- if self.updtsource is None:
+ if len(self.updtsources) == 0:
self.updttime = None
else :
self.updttime = time(11, 30)
@@ -513,15 +550,21 @@ class Asset(ModelSQL, ModelView):
"""
pool = Pool()
Asset = pool.get('investment.asset')
+ AssetSourceRel = pool.get('investment.asset_source_rel')
Rate = pool.get('investment.rate')
tab_asset = Asset.__table__()
tab_rate = Rate.__table__()
+ tab_rel = AssetSourceRel.__table__()
context = Transaction().context
query_date = context.get('qdate', CurrentDate() - Literal(1))
# 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,
type_ = 'LEFT OUTER',
).select(
@@ -531,7 +574,6 @@ class Asset(ModelSQL, ModelView):
tab_asset.updttime,
distinct_on = [tab_asset.id],
order_by = [tab_asset.id, tab_rate.date.desc],
- where=tab_asset.updtsource != None,
)
query = tab_date.select(
@@ -768,27 +810,18 @@ class Asset(ModelSQL, ModelView):
]):
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
+
+
+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
diff --git a/locale/de.po b/locale/de.po
index c100853..ac567f4 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -182,13 +182,13 @@ msgctxt "help:investment.asset,date:"
msgid "Date of current rate"
msgstr "Datum des aktuellen Kurses"
-msgctxt "field:investment.asset,updtsource:"
-msgid "Update Source"
-msgstr "Kursquelle"
+msgctxt "field:investment.asset,updtsources:"
+msgid "Update Sources"
+msgstr "Kursquellen"
-msgctxt "help:investment.asset,updtsource:"
-msgid "Select a source for the course update."
-msgstr "Wählen Sie eine Quelle für die Kursaktualisierung aus."
+msgctxt "help:investment.asset,updtsources:"
+msgid "Select sources for the course update. The course sources are tried until a valid value has been read."
+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:"
msgid "Time"
@@ -251,6 +251,22 @@ msgid "Mon - Sun"
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 #
#####################
diff --git a/locale/en.po b/locale/en.po
index 22530ee..f35f434 100644
--- a/locale/en.po
+++ b/locale/en.po
@@ -154,13 +154,13 @@ msgctxt "help:investment.asset,date:"
msgid "Date of current rate"
msgstr "Date of current rate"
-msgctxt "field:investment.asset,updtsource:"
-msgid "Update Source"
-msgstr "Update Source"
+msgctxt "field:investment.asset,updtsources:"
+msgid "Update Sources"
+msgstr "Update Sources"
-msgctxt "help:investment.asset,updtsource:"
-msgid "Select a source for the course update."
-msgstr "Select a source for the course update."
+msgctxt "help:investment.asset,updtsources:"
+msgid "Select sources for the course update. The course sources are tried until a valid value has been read."
+msgstr "Select sources for the course update. The course sources are tried until a valid value has been read."
msgctxt "field:investment.asset,updttime:"
msgid "Time"
@@ -222,6 +222,18 @@ msgctxt "selection:investment.asset,updtdays:"
msgid "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:"
msgid "Online Source"
msgstr "Online Source"
diff --git a/onlinesource.py b/onlinesource.py
index 125cf6b..5f551cc 100644
--- a/onlinesource.py
+++ b/onlinesource.py
@@ -222,48 +222,56 @@ class OnlineSource(ModelSQL, ModelView):
"""
pool = Pool()
Rate = pool.get('investment.rate')
+ IrDate = pool.get('ir.date')
- if asset.updtsource is None:
+ if len(asset.updtsources) == 0:
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:
- # check result - same code?
- code = rate_data.get('code', None)
- if code:
- asset_code = getattr(asset, {
- 'isin': 'isin',
- '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
+ for updtsource in asset.updtsources:
+ rate_data = cls.read_from_website(
+ updtsource,
+ isin = asset.isin,
+ nsin = asset.wkn,
+ symbol = asset.secsymb,
+ )
- 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
+ if len(updtsource.rgxident or '') > 0:
+ # check result - same code?
+ code = rate_data.get('code', None)
+ if code:
+ asset_code = getattr(asset, {
+ 'isin': 'isin',
+ 'nsin': 'wkn',
+ 'symbol': 'secsymb',
+ }[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,
+ })
+ 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
def get_regex_result(self, html_text, field_name):
diff --git a/tests/test_asset.py b/tests/test_asset.py
index 1d65593..798518f 100644
--- a/tests/test_asset.py
+++ b/tests/test_asset.py
@@ -568,18 +568,19 @@ class AssetTestCase(ModuleTestCase):
'name': 'Source 1',
}])
- self.assertEqual(asset.updtsource, None)
+ self.assertEqual(len(asset.updtsources), 0)
self.assertEqual(asset.updttime, time(14,0))
- asset.updtsource = o_source
+ asset.updtsources = [o_source]
asset.updttime = time(10, 45)
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))
- asset.updtsource = None
- asset.on_change_updtsource()
- self.assertEqual(asset.updtsource, None)
+ asset.updtsources = []
+ asset.on_change_updtsources()
+ self.assertEqual(len(asset.updtsources), 0)
self.assertEqual(asset.updttime, None)
@with_transaction()
@@ -606,7 +607,7 @@ class AssetTestCase(ModuleTestCase):
Asset.write(*[
[asset],
{
- 'updtsource': o_source.id,
+ 'updtsources': [('add', [o_source.id])],
'updttime': time(10, 45),
}])
@@ -616,7 +617,8 @@ class AssetTestCase(ModuleTestCase):
# re-read to make context work
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(len(asset2.rates), 0)
# qdate = 2022-10-14 simulates existence of record at this day
@@ -643,7 +645,7 @@ class AssetTestCase(ModuleTestCase):
self.assertEqual(len(asset.rates), 1)
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(len(asset.rates), 1)
self.assertEqual(asset.rates[0].date, date(2022, 10, 17))
@@ -668,7 +670,7 @@ class AssetTestCase(ModuleTestCase):
self.assertEqual(len(asset.rates), 2)
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(len(asset2.rates), 2)
self.assertEqual(asset2.rates[0].date, date(2022, 10, 18))
diff --git a/tests/test_source.py b/tests/test_source.py
index 0ce1e92..630f4be 100644
--- a/tests/test_source.py
+++ b/tests/test_source.py
@@ -64,7 +64,7 @@ class SourceTestCase(ModuleTestCase):
Asset.write(*[
[asset],
{
- 'updtsource': osource.id,
+ 'updtsources': [('add', [osource.id])],
}])
with Transaction().set_context({
@@ -76,7 +76,8 @@ class SourceTestCase(ModuleTestCase):
self.assertEqual(asset2.isin, 'XC0009655157')
self.assertEqual(asset2.secsymb, '1472977')
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.nextupdate, datetime(2022, 10, 3, 14, 0))
self.assertEqual(len(asset.rates), 0)
diff --git a/view/asset_form.xml b/view/asset_form.xml
index ec517b7..081304e 100644
--- a/view/asset_form.xml
+++ b/view/asset_form.xml
@@ -57,14 +57,12 @@ full copyright notices and license terms. -->
-
-
-
-
+
+