Compare commits

...

12 commits

Author SHA1 Message Date
Frederik Jaeckel
266589ced7 Version 7.0.13 2024-01-03 21:45:44 +01:00
Frederik Jaeckel
239114a0c1 fix sorting/searcher of field 'yield_balance' 2024-01-03 21:38:33 +01:00
Frederik Jaeckel
c6e054e1e4 Etikett ver 7.0.12 zum Änderungssatz 15795f33114c hinzugefügt 2023-12-31 10:54:53 +01:00
Frederik Jaeckel
38349c989a Version 7.0.12 2023-12-31 10:54:43 +01:00
Frederik Jaeckel
aefea56353 add sorting 2023-12-30 11:44:33 +01:00
Frederik Jaeckel
9f5c7c6b7d add columns to cashbook tree/list-view 2023-12-30 11:18:49 +01:00
Frederik Jaeckel
8ec7026259 add update of cashbooks on update of asset-rates 2023-12-30 10:57:17 +01:00
Frederik Jaeckel
8c2fb8ed7c cashbook: optimize for speed for checking rows 2023-12-29 23:09:00 +01:00
Frederik Jaeckel
246f035417 add worker-based precalculation of cashbook-values 2023-12-29 23:07:39 +01:00
Frederik Jaeckel
0bc55b8076 remove caching 2023-12-23 10:44:55 +01:00
Frederik Jaeckel
3ea35ea1e3 Etikett ver 7.0.11 zum Änderungssatz 5547a976f370 hinzugefügt 2023-12-06 21:35:28 +01:00
Frederik Jaeckel
7099289345 Version 7.0.11 2023-12-06 21:35:12 +01:00
14 changed files with 840 additions and 154 deletions

View file

@ -23,6 +23,16 @@ You can monitor trading fees, dividends and sales profits.
Changes
=======
*7.0.0 - 06.12.2023*
*7.0.13 - 03.01.2024*
- fix: sorting/searcher of field yield-balance
*7.0.12 - 31.12.2023*
- remove caching
- add worker-based precalculation of cashbook-values
- add columns to cashbook list/tree view
*7.0.11 - 06.12.2023*
- compatibility to Tryton 7.0

View file

@ -11,6 +11,7 @@ from .line import Line
from .splitline import SplitLine
from .assetsetting import AssetSetting
from .asset import AssetRate
from .valuestore import ValueStore
def register():
@ -22,4 +23,5 @@ def register():
SplitLine,
Reconciliation,
AssetSetting,
ValueStore,
module='cashbook_investment', type_='model')

View file

@ -3,8 +3,7 @@
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
from trytond.pool import Pool, PoolMeta
CACHEKEY_ASSETRATE = 'assetrate-%s'
from trytond.pool import PoolMeta, Pool
class AssetRate(metaclass=PoolMeta):
@ -14,34 +13,52 @@ class AssetRate(metaclass=PoolMeta):
def create(cls, vlist):
""" update cache-value
"""
MemCache = Pool().get('cashbook.memcache')
pool = Pool()
Cashbook = pool.get('cashbook.book')
ValueStore = pool.get('cashbook.values')
records = super(AssetRate, cls).create(vlist)
for rate in records:
MemCache.record_update(CACHEKEY_ASSETRATE % rate.asset.id, rate)
ValueStore.update_books(
ValueStore.get_book_by_books(
Cashbook.search([
('asset', 'in', [
x.asset.id for x in records])])))
return records
@classmethod
def write(cls, *args):
""" update cache-value
"""
MemCache = Pool().get('cashbook.memcache')
pool = Pool()
Cashbook = pool.get('cashbook.book')
ValueStore = pool.get('cashbook.values')
actions = iter(args)
all_rates = []
for rates, values in zip(actions, actions):
all_rates.extend(rates)
super(AssetRate, cls).write(*args)
actions = iter(args)
for rates, values in zip(actions, actions):
for rate in rates:
MemCache.record_update(CACHEKEY_ASSETRATE % rate.asset.id, rate)
ValueStore.update_books(
ValueStore.get_book_by_books(
Cashbook.search([
('asset', 'in', [
x.asset.id for x in all_rates])])))
@classmethod
def delete(cls, records):
""" set cache to None
"""
MemCache = Pool().get('cashbook.memcache')
pool = Pool()
Cashbook = pool.get('cashbook.book')
ValueStore = pool.get('cashbook.values')
books = ValueStore.get_book_by_books(Cashbook.search([
('asset', 'in', [x.asset.id for x in records])]))
for record in records:
MemCache.record_update(CACHEKEY_ASSETRATE % record.asset.id, None)
super(AssetRate, cls).delete(records)
ValueStore.update_books(books)
# end

View file

@ -5,7 +5,6 @@
from trytond.model import ModelSingleton, ModelView, ModelSQL, fields
from trytond.pool import Pool
class AssetSetting(ModelSingleton, ModelSQL, ModelView):
@ -25,13 +24,4 @@ class AssetSetting(ModelSingleton, ModelSQL, ModelView):
model_name='cashbook.book', ondelete='RESTRICT',
help='Profit and loss on sale of assets are recorded in the cash book.')
@classmethod
def write(cls, *args):
""" clear cache-values
"""
MemCache = Pool().get('cashbook.memcache')
MemCache._cashbook_value_cache.clear_all()
super(AssetSetting, cls).write(*args)
# end AssetSetting

404
book.py
View file

@ -5,37 +5,20 @@
from trytond.model import fields, SymbolMixin, Index
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Or, Len, Bool, If
from trytond.pyson import Eval, Or, Bool, If
from trytond.modules.cashbook.book import STATES2, DEPENDS2
from trytond.transaction import Transaction
from trytond.report import Report
from trytond.config import config
from trytond.exceptions import UserError
from trytond.i18n import gettext
from decimal import Decimal
from datetime import timedelta
from sql import Literal
from sql.functions import CurrentDate
from sql.aggregate import Sum
from sql.conditionals import Case, Coalesce
from trytond.modules.cashbook.model import sub_ids_hierarchical,\
CACHEKEY_CURRENCY, AnyInArray
from .asset import CACHEKEY_ASSETRATE
# enable/disable caching of cachekey for 'currency.rate'
if config.get(
'cashbook', 'cache_currency',
default='yes').lower() in ['yes', '1', 'true']:
ENA_CURRKEY = True
else:
ENA_CURRKEY = False
# enable/disable caching of cachekey for 'currency.rate'
if config.get(
'cashbook', 'cache_asset',
default='yes').lower() in ['yes', '1', 'true']:
ENA_ASSETKEY = True
else:
ENA_ASSETKEY = False
from trytond.modules.cashbook.model import (
sub_ids_hierarchical, AnyInArray)
class Book(SymbolMixin, metaclass=PoolMeta):
@ -49,8 +32,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'invisible': Eval('feature', '') != 'asset',
'readonly': Or(
STATES2['readonly'],
Len(Eval('lines')) > 0)},
depends=DEPENDS2+['feature', 'lines'])
Eval('has_lines', False))},
depends=DEPENDS2+['feature', 'has_lines'])
quantity_digits = fields.Integer(
string='Digits', help='Quantity Digits',
domain=[
@ -61,8 +44,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'invisible': Eval('feature', '') != 'asset',
'readonly': Or(
STATES2['readonly'],
Len(Eval('lines')) > 0)},
depends=DEPENDS2+['feature', 'lines'])
Eval('has_lines', False))},
depends=DEPENDS2+['feature', 'has_lines'])
asset_uomcat = fields.Function(fields.Many2One(
string='UOM Category', readonly=True,
model_name='product.uom.category',
@ -76,8 +59,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'invisible': Eval('feature', '') != 'asset',
'readonly': Or(
STATES2['readonly'],
Len(Eval('lines')) > 0)},
depends=DEPENDS2+['feature', 'lines', 'asset_uomcat'])
Eval('has_lines', False))},
depends=DEPENDS2+['feature', 'asset_uomcat', 'has_lines'])
symbol = fields.Function(fields.Char(
string='Symbol', readonly=True), 'on_change_with_symbol')
asset_symbol = fields.Function(fields.Many2One(
@ -87,12 +70,14 @@ class Book(SymbolMixin, metaclass=PoolMeta):
string='Quantity', help='Quantity of assets until to date',
readonly=True, digits=(16, Eval('quantity_digits', 4)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['quantity_digits', 'feature']), 'get_asset_quantity')
depends=['quantity_digits', 'feature']),
'get_asset_quantity', searcher='search_asset_quantity')
quantity_all = fields.Function(fields.Numeric(
string='Total Quantity', help='Total quantity of all assets',
readonly=True, digits=(16, Eval('quantity_digits', 4)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['quantity_digits', 'feature']), 'get_asset_quantity')
depends=['quantity_digits', 'feature']),
'get_asset_quantity', searcher='search_asset_quantity')
current_value = fields.Function(fields.Numeric(
string='Value',
help='Valuation of the investment based on the current ' +
@ -100,7 +85,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': ~Eval('show_performance', False)},
depends=['currency_digits', 'show_performance']),
'get_asset_quantity')
'get_asset_quantity', searcher='search_asset_quantity')
current_value_ref = fields.Function(fields.Numeric(
string='Value (Ref.)',
help='Valuation of the investment based on the current stock' +
@ -111,7 +96,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
~Eval('show_performance', False),
~Bool(Eval('company_currency', -1)))},
depends=['currency_digits', 'show_performance', 'company_currency']),
'get_asset_quantity')
'get_asset_quantity', searcher='search_asset_quantity')
# performance
diff_amount = fields.Function(fields.Numeric(
@ -120,14 +105,14 @@ class Book(SymbolMixin, metaclass=PoolMeta):
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': ~Eval('show_performance', False)},
depends=['currency_digits', 'show_performance']),
'get_asset_quantity')
'get_asset_quantity', searcher='search_asset_quantity')
diff_percent = fields.Function(fields.Numeric(
string='Percent',
help='percentage performance since acquisition',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': ~Eval('show_performance', False)},
depends=['currency_digits', 'show_performance']),
'get_asset_quantity')
'get_asset_quantity', searcher='search_asset_quantity')
show_performance = fields.Function(fields.Boolean(
string='Performance', readonly=True), 'on_change_with_show_performance')
current_rate = fields.Function(fields.Numeric(
@ -136,54 +121,63 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'exchange price.',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_asset_quantity')
depends=['currency_digits', 'feature']),
'get_asset_quantity', searcher='search_asset_quantity')
purchase_amount = fields.Function(fields.Numeric(
string='Purchase Amount',
help='Total purchase amount, from shares and fees.',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_asset_quantity')
depends=['currency_digits', 'feature']),
'get_asset_quantity', searcher='search_asset_quantity')
# yield
yield_dividend_total = fields.Function(fields.Numeric(
string='Dividend', help='Total dividends received',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
depends=['currency_digits', 'feature']),
'get_yield_data', searcher='search_asset_quantity')
yield_dividend_12m = fields.Function(fields.Numeric(
string='Dividend 1y',
help='Dividends received in the last twelve months',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
depends=['currency_digits', 'feature']),
'get_yield_data', searcher='search_asset_quantity')
yield_fee_total = fields.Function(fields.Numeric(
string='Trade Fee', help='Total trade fees payed',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
depends=['currency_digits', 'feature']),
'get_yield_data', searcher='search_asset_quantity')
yield_fee_12m = fields.Function(fields.Numeric(
string='Trade Fee 1y',
help='Trade fees payed in the last twelve month',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
depends=['currency_digits', 'feature']),
'get_yield_data', searcher='search_asset_quantity')
yield_sales = fields.Function(fields.Numeric(
string='Sales', help='Total profit or loss on sale of shares.',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
depends=['currency_digits', 'feature']),
'get_yield_data', searcher='search_asset_quantity')
yield_sales_12m = fields.Function(fields.Numeric(
string='Sales 1y',
help='Total profit or loss on sale of shares in the last twelve month.',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
depends=['currency_digits', 'feature']),
'get_yield_data', searcher='search_asset_quantity')
yield_balance = fields.Function(fields.Numeric(
string='Total Yield',
help='Total income: price gain + dividends + sales gains - fees',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'on_change_with_yield_balance')
depends=['currency_digits', 'feature']),
'get_yield_balance_data', searcher='search_asset_quantity')
@classmethod
def __setup__(cls):
@ -221,6 +215,109 @@ class Book(SymbolMixin, metaclass=PoolMeta):
}
return recname
@classmethod
def work_order_assets(cls, tables, field_name):
""" get order-query
"""
Book2 = Pool().get('cashbook.book')
if 'date' in Transaction().context:
raise UserError(gettext(
'cashbook.msg_nosearch_with_date',
fname=field_name, model=Book2.__name__))
return Book2.work_order_balance(tables, field_name)
@staticmethod
def order_current_value(tables):
""" order by current_value
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'current_value')
@staticmethod
def order_purchase_amount(tables):
""" order by purchase_amount
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'purchase_amount')
@staticmethod
def order_diff_amount(tables):
""" order by diff_amount
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'diff_amount')
@staticmethod
def order_yield_balance(tables):
""" order by yield_balance
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'yield_balance')
@staticmethod
def order_diff_percent(tables):
""" order by diff_percent
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'diff_percent')
@staticmethod
def order_quantity(tables):
""" order by quantity
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'quantity')
@staticmethod
def order_quantity_all(tables):
""" order by quantity_all
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'quantity_all')
@staticmethod
def order_yield_sales(tables):
""" order by yield_sales
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'yield_sales')
@staticmethod
def order_yield_sales_12m(tables):
""" order by yield_sales_12m
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'yield_sales_12m')
@staticmethod
def order_yield_dividend_total(tables):
""" order by yield_dividend_total
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'yield_dividend_total')
@staticmethod
def order_yield_dividend_12m(tables):
""" order by yield_dividend_12m
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'yield_dividend_12m')
@staticmethod
def order_yield_fee_total(tables):
""" order by yield_fee_total
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'yield_fee_total')
@staticmethod
def order_yield_fee_12m(tables):
""" order by yield_fee_12m
"""
Book2 = Pool().get('cashbook.book')
return Book2.work_order_assets(tables, 'yield_fee_12m')
@fields.depends('asset', 'quantity_uom')
def on_change_asset(self):
""" get uom from asset
@ -234,15 +331,39 @@ class Book(SymbolMixin, metaclass=PoolMeta):
"""
return 4
@fields.depends('yield_sales', 'yield_dividend_total', 'diff_amount')
def on_change_with_yield_balance(self, name=None):
@classmethod
def get_yield_balance_data(cls, cashbooks, names):
""" calculate yield total
fee is already contained in 'diff_amount'
"""
context = Transaction().context
result = {x: {y.id: Decimal('0.0') for y in cashbooks} for x in names}
query_date = context.get('date', None)
if context.get(
'compute_yield_balance',
False) or query_date is not None:
amounts = {}
amounts.update(cls.get_asset_quantity(cashbooks, ['diff_amount']))
amounts.update(cls.get_yield_data(
cashbooks,
['yield_dividend_total', 'yield_sales']))
for cashbook in cashbooks:
sum_lst = [
self.diff_amount, self.yield_dividend_total, self.yield_sales]
amounts[x][cashbook.id]
for x in [
'diff_amount', 'yield_dividend_total',
'yield_sales']]
sum2 = sum([x for x in sum_lst if x is not None])
return sum2
result['yield_balance'][cashbook.id] = sum2
else:
for cashbook in cashbooks:
for value in cashbook.value_store:
if value.field_name in names:
result[value.field_name][cashbook.id] = value.numvalue
return result
@classmethod
def get_yield_data_sql(cls, date_from=None, date_to=None):
@ -287,11 +408,29 @@ class Book(SymbolMixin, metaclass=PoolMeta):
@classmethod
def get_yield_data(cls, cashbooks, names):
""" get yield data - stored or computed
"""
context = Transaction().context
result = {x: {y.id: Decimal('0.0') for y in cashbooks} for x in names}
# return computed values if 'date' is in context
query_date = context.get('date', None)
if query_date is not None:
return cls.get_yield_values(cashbooks, names)
for cashbook in cashbooks:
for value in cashbook.value_store:
if value.field_name in names:
result[value.field_name][cashbook.id] = value.numvalue
return result
@classmethod
def get_yield_values(cls, cashbooks, names):
""" collect yield data
"""
pool = Pool()
IrDate = pool.get('ir.date')
MemCache = pool.get('cashbook.memcache')
cursor = Transaction().connection.cursor()
context = Transaction().context
result = {
@ -309,40 +448,13 @@ class Book(SymbolMixin, metaclass=PoolMeta):
).quantize(Decimal(str(1/10 ** digits)))
query_date = context.get('date', IrDate.today())
cache_keys = {
x.id: MemCache.get_key_by_record(
name='get_yield_data',
record=x,
query=[{
'model': 'cashbook.line',
'query': [('cashbook.parent', 'child_of', [x.id])],
}, {
'model': 'currency.currency.rate',
'query': [('currency.id', '=', x.currency.id)],
'cachekey' if ENA_CURRKEY else 'disabled':
CACHEKEY_CURRENCY % x.currency.id,
}, {
'model': 'investment.rate',
'query': [('asset.id', '=', x.asset.id)],
'cachekey' if ENA_ASSETKEY else 'disabled':
CACHEKEY_ASSETRATE % x.asset.id,
} if x.asset is not None else {}],
addkeys=[query_date.isoformat()])
for x in cashbooks
}
# read from cache
(todo_cashbook, result) = MemCache.read_from_cache(
cashbooks, cache_keys, names, result)
if len(todo_cashbook) == 0:
return result
# results for 'total'
records_total = []
records_12m = []
if len(todo_cashbook) > 0:
if cashbooks:
(tab_book1, query_total) = cls.get_yield_data_sql()
query_total.where &= tab_book1.id.in_([x.id for x in todo_cashbook])
query_total.where &= tab_book1.id.in_([x.id for x in cashbooks])
cursor.execute(*query_total)
records_total = cursor.fetchall()
@ -351,7 +463,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
date_to=query_date,
date_from=query_date - timedelta(days=365),
)
query_12m.where &= tab_book2.id.in_([x.id for x in todo_cashbook])
query_12m.where &= tab_book2.id.in_([x.id for x in cashbooks])
cursor.execute(*query_12m)
records_12m = cursor.fetchall()
@ -370,9 +482,6 @@ class Book(SymbolMixin, metaclass=PoolMeta):
record[2], record[4])
result['yield_sales_12m'][record[0]] = quantize_val(
record[3], record[4])
# store to cache
MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook)
return {x: result[x] for x in names}
@classmethod
@ -395,7 +504,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
(tab_line_yield, query_yield) = Line.get_yield_data_sql()
context = Transaction().context
query_date = context.get('qdate', CurrentDate())
query_date = context.get('date', CurrentDate())
query = tab_book.join(
tab_line,
condition=(tab_book.id == tab_line.cashbook),
@ -447,7 +556,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
return (query, tab_book)
@classmethod
def get_asset_quantity(cls, cashbooks, names):
def get_asset_quantity_values(cls, cashbooks, names):
""" get quantities
field: quantity, quantity_all, current_value,
current_value_ref, diff_amount, diff_percent,
@ -457,10 +566,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
CBook = pool.get('cashbook.book')
Uom = pool.get('product.uom')
Currency = pool.get('currency.currency')
IrDate = pool.get('ir.date')
MemCache = pool.get('cashbook.memcache')
cursor = Transaction().connection.cursor()
context = Transaction().context
(query, tab_book) = cls.get_asset_quantity_sql()
company_currency = CBook.default_currency()
@ -473,37 +579,6 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'digits']
}
cache_keys = {
x.id: MemCache.get_key_by_record(
name='get_asset_quantity',
record=x,
query=[{
'model': 'cashbook.line',
'query': [('cashbook.parent', 'child_of', [x.id])],
}, {
'model': 'currency.currency.rate',
'query': [('currency.id', '=', x.currency.id)],
'cachekey' if ENA_CURRKEY else 'disabled':
CACHEKEY_CURRENCY % x.currency.id,
}, {
'model': 'investment.rate',
'query': [('asset.id', '=', x.asset.id)],
'cachekey' if ENA_ASSETKEY else 'disabled':
CACHEKEY_ASSETRATE % x.asset.id,
} if x.asset is not None else {}],
addkeys=[
str(company_currency),
str(context.get('qdate', IrDate.today()).toordinal()),
])
for x in cashbooks
}
# read from cache
(todo_cashbook, result) = MemCache.read_from_cache(
cashbooks, cache_keys, names, result)
if len(todo_cashbook) == 0:
return result
def values_from_record(rdata):
""" compute values for record
"""
@ -548,8 +623,15 @@ class Book(SymbolMixin, metaclass=PoolMeta):
if company_currency is not None else rdata[4]),
})
ids_assetbooks = [x.id for x in cashbooks if x.btype is not None]
ids_nonebtypes = [x.id for x in cashbooks if x.btype is None]
ids_assetbooks = []
ids_nonebtypes = []
for x in cashbooks:
if x.btype is None:
if x.id not in ids_nonebtypes:
ids_nonebtypes.append(x.id)
else:
if x.id not in ids_assetbooks:
ids_assetbooks.append(x.id)
# get values of asset-cashbooks in 'cashbooks' of type=asset
if len(ids_assetbooks) > 0:
@ -644,11 +726,89 @@ class Book(SymbolMixin, metaclass=PoolMeta):
Decimal('100.0') * c_val / p_amount - Decimal('100.0')
).quantize(Decimal(str(1/10 ** digits)))
result['digits'][id_book] = None
# store to cache
MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook)
return {x: result[x] for x in names}
@classmethod
def get_asset_quantity(cls, cashbooks, names):
""" get quantities - stored or computed
"""
context = Transaction().context
result = {x: {y.id: Decimal('0.0') for y in cashbooks} for x in names}
# return computed values if 'date' is in context
query_date = context.get('date', None)
if query_date is not None:
return cls.get_asset_quantity_values(cashbooks, names)
for cashbook in cashbooks:
for value in cashbook.value_store:
if value.field_name in names:
result[value.field_name][cashbook.id] = value.numvalue
return result
@classmethod
def search_asset_quantity(cls, name, clause):
""" search in stored data
"""
ValueStore = Pool().get('cashbook.values')
context = Transaction().context
query_date = context.get('date', None)
if query_date is not None:
raise UserError(gettext(
'cashbook.msg_nosearch_with_date',
fname=name, model=cls.__name__))
else:
value_query = ValueStore.search([
('field_name', '=', clause[0]),
('numvalue',) + tuple(clause[1:]),
],
query=True)
return [('value_store', 'in', value_query)]
@classmethod
def valuestore_fields(cls):
""" field to update
"""
result = super(Book, cls).valuestore_fields()
# get_asset_quantity_values
result.extend([
'quantity', 'quantity_all', 'current_value', 'current_value_ref',
'diff_amount', 'diff_percent', 'current_rate', 'purchase_amount',
'yield_fee_total', 'yield_dividend_total', 'yield_sales',
'yield_fee_12m', 'yield_dividend_12m', 'yield_sales_12m',
'yield_balance'])
return result
@classmethod
def valuestore_update_records(cls, records):
""" compute current values of records,
store to global storage
"""
ValStore = Pool().get('cashbook.values')
super(Book, cls).valuestore_update_records(records)
if records:
ValStore.update_values(
cls.get_asset_quantity_values(
records, [
'quantity', 'quantity_all', 'current_value',
'current_value_ref', 'diff_amount', 'diff_percent',
'current_rate', 'purchase_amount']))
ValStore.update_values(
cls.get_yield_values(
records, [
'yield_fee_total', 'yield_dividend_total',
'yield_sales', 'yield_fee_12m', 'yield_dividend_12m',
'yield_sales_12m']))
with Transaction().set_context({
'compute_yield_balance': True}):
ValStore.update_values(
cls.get_yield_balance_data(records, ['yield_balance']))
@fields.depends('id')
def on_change_with_show_performance(self, name=None):
""" return True if current or subordered cashbooks

View file

@ -48,6 +48,25 @@ class CbInvTestCase(object):
self.assertEqual(book.quantity_digits, 4)
self.assertEqual(book.show_performance, True)
# run sorter
books = Book.search(
[],
order=[
('current_value', 'ASC'),
('purchase_amount', 'ASC'),
('diff_amount', 'ASC'),
('yield_balance', 'ASC'),
('diff_percent', 'ASC'),
('quantity', 'ASC'),
('quantity_all', 'ASC'),
('yield_sales', 'ASC'),
('yield_sales_12m', 'ASC'),
('yield_dividend_total', 'ASC'),
('yield_dividend_12m', 'ASC'),
('yield_fee_total', 'ASC'),
('yield_fee_12m', 'ASC'),
])
@with_transaction()
def test_assetbook_aggregated_values(self):
""" create cashbooks with hierarchy, add lines,
@ -174,6 +193,24 @@ class CbInvTestCase(object):
self.assertEqual(books[0].diff_amount, Decimal('-5.49'))
self.assertEqual(books[0].diff_percent, Decimal('-18.74'))
# searcher
self.assertEqual(Book.search_count([
('current_value', '=', Decimal('23.8'))]), 1)
self.assertEqual(Book.search_count([
('current_value_ref', '=', Decimal('23.8'))]), 1)
self.assertEqual(Book.search_count([
('diff_amount', '=', Decimal('-5.49'))]), 1)
self.assertEqual(Book.search_count([
('diff_percent', '=', Decimal('-18.74'))]), 1)
self.assertEqual(Book.search_count([
('quantity', '=', Decimal('1.0'))]), 2)
self.assertEqual(Book.search_count([
('quantity_all', '=', Decimal('1.0'))]), 2)
self.assertEqual(Book.search_count([
('current_rate', '=', Decimal('11.9'))]), 1)
self.assertEqual(Book.search_count([
('purchase_amount', '=', Decimal('15.0'))]), 2)
self.assertEqual(len(books[0].childs), 4)
self.assertEqual(
@ -327,10 +364,11 @@ class CbInvTestCase(object):
# wf --> check
Line.wfcheck(book.lines)
self.prep_valstore_run_worker()
# check quantities at cashbook
with Transaction().set_context({
'qdate': date(2022, 5, 5)}):
'date': date(2022, 5, 5)}):
book2, = Book.browse([book])
self.assertEqual(book.asset.rate, Decimal('2.8')) # usd
self.assertEqual(book2.quantity, Decimal('1.453'))
@ -340,7 +378,7 @@ class CbInvTestCase(object):
self.assertEqual(book2.current_value_ref, Decimal('3.87'))
with Transaction().set_context({
'qdate': date(2022, 5, 12)}):
'date': date(2022, 5, 12)}):
book2, = Book.browse([book])
self.assertEqual(book2.quantity, Decimal('4.753'))
self.assertEqual(book2.quantity_all, Decimal('4.753'))
@ -399,6 +437,17 @@ class CbInvTestCase(object):
'Aurum | 1,750.0000 usd/oz | 05/01/2022')
(usd, euro) = self.prep_2nd_currency(company)
usd.rates[0].date = date(2022, 5, 1)
usd.rates[0].save()
self.assertEqual(len(usd.rates), 1)
self.assertEqual(usd.rates[0].date, date(2022, 5, 1))
euro.rates[0].date = date(2022, 5, 1)
euro.rates[0].save()
self.assertEqual(len(euro.rates), 1)
self.assertEqual(euro.rates[0].date, date(2022, 5, 1))
self.assertEqual(company.currency.rec_name, 'Euro')
self.assertEqual(asset.symbol, 'usd/oz')
@ -441,7 +490,7 @@ class CbInvTestCase(object):
# check quantities at cashbook
with Transaction().set_context({
'qdate': date(2022, 5, 1)}):
'date': date(2022, 5, 1)}):
book2, = Book.browse([book])
self.assertEqual(book.asset.rate, Decimal('1750.0')) # usd
self.assertEqual(book2.quantity, Decimal('20.0'))
@ -508,6 +557,16 @@ class CbInvTestCase(object):
'Aurum | 1,750.0000 usd/oz | 05/01/2022')
(usd, euro) = self.prep_2nd_currency(company)
usd.rates[0].date = date(2022, 5, 1)
usd.rates[0].save()
self.assertEqual(len(usd.rates), 1)
self.assertEqual(usd.rates[0].date, date(2022, 5, 1))
euro.rates[0].date = date(2022, 5, 1)
euro.rates[0].save()
self.assertEqual(len(euro.rates), 1)
self.assertEqual(euro.rates[0].date, date(2022, 5, 1))
self.assertEqual(company.currency.rec_name, 'Euro')
self.assertEqual(asset.symbol, 'usd/oz')
chf, = Currency.create([{
@ -562,7 +621,7 @@ class CbInvTestCase(object):
# check quantities at cashbook
with Transaction().set_context({
'qdate': date(2022, 5, 1)}):
'date': date(2022, 5, 1)}):
book2, = Book.browse([book])
self.assertEqual(book.asset.rate, Decimal('1750.0')) # usd
self.assertEqual(book2.quantity, Decimal('20.0'))
@ -924,6 +983,7 @@ class CbInvTestCase(object):
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.prep_valstore_run_worker()
self.assertEqual(book.rec_name, 'Book 1 | -1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
@ -1069,6 +1129,7 @@ class CbInvTestCase(object):
self.assertEqual(len(book2.lines), 0)
Line.wfcheck(list(book1.lines))
self.prep_valstore_run_worker()
self.assertEqual(
book1.rec_name,
@ -1167,6 +1228,7 @@ class CbInvTestCase(object):
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.prep_valstore_run_worker()
self.assertEqual(book.rec_name, 'Book 1 | 1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
@ -1314,6 +1376,7 @@ class CbInvTestCase(object):
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.prep_valstore_run_worker()
self.assertEqual(
book.rec_name,
@ -1498,6 +1561,7 @@ class CbInvTestCase(object):
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.prep_valstore_run_worker()
self.assertEqual(
book.rec_name,
@ -1855,6 +1919,7 @@ class CbInvTestCase(object):
self.assertEqual(len(books[1].lines), 0)
Line.wfcheck([books[0].lines[0]])
self.prep_valstore_run_worker()
self.assertEqual(
books[0].rec_name,
@ -2010,6 +2075,7 @@ class CbInvTestCase(object):
self.assertEqual(len(books[1].lines), 0)
Line.wfcheck([books[0].lines[0]])
self.prep_valstore_run_worker()
self.assertEqual(
books[0].rec_name,
@ -2192,6 +2258,7 @@ class CbInvTestCase(object):
self.assertEqual(len(books[1].lines), 0)
Line.wfcheck([books[0].lines[0]])
self.prep_valstore_run_worker()
self.assertEqual(
books[0].rec_name,
@ -2531,6 +2598,7 @@ class CbInvTestCase(object):
self.assertEqual(len(books[1].lines), 0)
Line.wfcheck([books[0].lines[0]])
self.prep_valstore_run_worker()
self.assertEqual(
books[0].rec_name,
@ -2690,6 +2758,7 @@ class CbInvTestCase(object):
self.assertEqual(len(books[1].lines), 0)
Line.wfcheck([books[0].lines[0]])
self.prep_valstore_run_worker()
self.assertEqual(books[0].rec_name, 'Book Cash | -11.00 usd | Open')
self.assertEqual(books[0].balance_all, Decimal('-11.0'))
@ -2882,6 +2951,7 @@ class CbInvTestCase(object):
self.assertEqual(len(books[1].lines), 0)
Line.wfcheck([books[0].lines[0]])
self.prep_valstore_run_worker()
self.assertEqual(
books[0].rec_name,

View file

@ -10,9 +10,11 @@ from trytond.modules.investment.tests.test_module import InvestmentTestCase
from .yieldtest import YieldTestCase
from .book import CbInvTestCase
from .reconciliation import ReconTestCase
from .valuestore import ValueStoreTestCase
class CashbookInvestmentTestCase(
ValueStoreTestCase,
CashbookTestCase,
InvestmentTestCase,
CbInvTestCase,

377
tests/valuestore.py Normal file
View file

@ -0,0 +1,377 @@
# -*- 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.tests.test_tryton import with_transaction
from trytond.pool import Pool
from trytond.transaction import Transaction
from datetime import date
from decimal import Decimal
class ValueStoreTestCase(object):
""" test update of cashbooks on update of asset
"""
@with_transaction()
def test_valstore_update_asset_rate(self):
""" update rate of asset, should update cashbook
"""
pool = Pool()
Book = pool.get('cashbook.book')
BType = pool.get('cashbook.type')
Asset = pool.get('investment.asset')
Queue = pool.get('ir.queue')
ValStore = pool.get('cashbook.values')
company = self.prep_company()
with Transaction().set_context({'company': company.id}):
types = self.prep_type()
BType.write(*[
[types],
{
'feature': 'asset',
}])
category = self.prep_category(cattype='in')
party = self.prep_party()
asset = self.prep_asset_item(
company=company,
product=self.prep_asset_product(name='Product 1'))
Asset.write(*[
[asset],
{
'rates': [('create', [{
'date': date(2022, 5, 1),
'rate': Decimal('2.5'),
}, {
'date': date(2022, 5, 2),
'rate': Decimal('2.8'),
}])],
}])
self.assertEqual(
asset.rec_name, 'Product 1 | 2.8000 usd/u | 05/02/2022')
(usd, euro) = self.prep_2nd_currency(company)
self.assertEqual(company.currency.rec_name, 'Euro')
self.assertEqual(asset.symbol, 'usd/u')
self.assertEqual(Queue.search_count([]), 0)
book, = Book.create([{
'start_date': date(2022, 4, 1),
'name': 'Book 1',
'btype': types.id,
'company': company.id,
'currency': euro.id,
'number_sequ': self.prep_sequence().id,
'asset': asset.id,
'quantity_uom': asset.uom.id,
'quantity_digits': 3,
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Text 1',
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('2.5'),
'party': party.id,
'quantity': Decimal('1.5'),
}])],
}])
# run worker
self.assertEqual(
ValStore.search_count([]),
len(Book.valuestore_fields()))
self.prep_valstore_run_worker()
self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.rec_name, 'Book 1 | 2.50 € | Open | 1.500 u')
self.assertEqual(len(book.lines), 1)
self.assertEqual(
book.lines[0].rec_name,
'05/01/2022|Rev|2.50 €|Text 1 [Cat1]|1.500 u')
values = ValStore.search([
('cashbook', '=', book.id)], order=[('field_name', 'ASC')])
self.assertEqual(len(values), len(Book.valuestore_fields()))
self.assertEqual(
values[0].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance|2.50|2')
self.assertEqual(
values[1].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance_all|2.50|2')
self.assertEqual(
values[2].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance_ref|2.50|2')
self.assertEqual(
values[3].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_rate|2.67|2')
self.assertEqual(
values[4].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_value|4.00|2')
self.assertEqual(
values[5].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_value_ref|4.00|2')
self.assertEqual(
values[6].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|diff_amount|1.50|2')
self.assertEqual(
values[7].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|diff_percent|60.00|2')
self.assertEqual(
values[8].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|purchase_amount|2.50|2')
self.assertEqual(
values[9].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|quantity|1.500|3')
self.assertEqual(
values[10].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|quantity_all|1.500|3')
self.assertEqual(
values[11].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_balance|4.00|2')
self.assertEqual(
values[12].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_12m|0.00|2')
self.assertEqual(
values[13].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_total|0.00|2')
self.assertEqual(
values[14].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_12m|0.00|2')
self.assertEqual(
values[15].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_total|0.00|2')
self.assertEqual(
values[16].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales|2.50|2')
self.assertEqual(
values[17].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales_12m|0.00|2')
# add rate
Asset.write(*[
[asset],
{
'rates': [('create', [{
'date': date(2022, 5, 10),
'rate': Decimal('3.0'),
}])],
}])
self.assertEqual(
asset.rec_name, 'Product 1 | 3.0000 usd/u | 05/10/2022')
# run worker
self.prep_valstore_run_worker()
values = ValStore.search([
('cashbook', '=', book.id)], order=[('field_name', 'ASC')])
self.assertEqual(len(values), len(Book.valuestore_fields()))
self.assertEqual(
values[0].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance|2.50|2')
self.assertEqual(
values[1].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance_all|2.50|2')
self.assertEqual(
values[2].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance_ref|2.50|2')
self.assertEqual(
values[3].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_rate|2.86|2')
self.assertEqual(
values[4].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_value|4.29|2')
self.assertEqual(
values[5].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_value_ref|4.29|2')
self.assertEqual(
values[6].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|diff_amount|1.79|2')
self.assertEqual(
values[7].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|diff_percent|71.60|2')
self.assertEqual(
values[8].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|purchase_amount|2.50|2')
self.assertEqual(
values[9].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|quantity|1.500|3')
self.assertEqual(
values[10].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|quantity_all|1.500|3')
self.assertEqual(
values[11].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_balance|4.29|2')
self.assertEqual(
values[12].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_12m|0.00|2')
self.assertEqual(
values[13].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_total|0.00|2')
self.assertEqual(
values[14].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_12m|0.00|2')
self.assertEqual(
values[15].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_total|0.00|2')
self.assertEqual(
values[16].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales|2.50|2')
self.assertEqual(
values[17].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales_12m|0.00|2')
# update rate
self.assertEqual(asset.rates[0].rate, Decimal('3.0'))
self.assertEqual(asset.rates[0].date, date(2022, 5, 10))
Asset.write(*[
[asset],
{
'rates': [('write', [asset.rates[0]], {
'rate': Decimal('3.5'),
})],
}])
self.assertEqual(
asset.rec_name, 'Product 1 | 3.5000 usd/u | 05/10/2022')
# run worker
self.prep_valstore_run_worker()
values = ValStore.search([
('cashbook', '=', book.id)], order=[('field_name', 'ASC')])
self.assertEqual(len(values), len(Book.valuestore_fields()))
self.assertEqual(
values[0].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance|2.50|2')
self.assertEqual(
values[1].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance_all|2.50|2')
self.assertEqual(
values[2].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance_ref|2.50|2')
self.assertEqual(
values[3].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_rate|3.33|2')
self.assertEqual(
values[4].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_value|5.00|2')
self.assertEqual(
values[5].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_value_ref|5.00|2')
self.assertEqual(
values[6].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|diff_amount|2.50|2')
self.assertEqual(
values[7].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|diff_percent|100.00|2')
self.assertEqual(
values[8].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|purchase_amount|2.50|2')
self.assertEqual(
values[9].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|quantity|1.500|3')
self.assertEqual(
values[10].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|quantity_all|1.500|3')
self.assertEqual(
values[11].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_balance|5.00|2')
self.assertEqual(
values[12].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_12m|0.00|2')
self.assertEqual(
values[13].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_total|0.00|2')
self.assertEqual(
values[14].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_12m|0.00|2')
self.assertEqual(
values[15].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_total|0.00|2')
self.assertEqual(
values[16].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales|2.50|2')
self.assertEqual(
values[17].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales_12m|0.00|2')
# delete rate
self.assertEqual(asset.rates[0].rate, Decimal('3.5'))
self.assertEqual(asset.rates[0].date, date(2022, 5, 10))
Asset.write(*[
[asset],
{
'rates': [('delete', [asset.rates[0].id])],
}])
self.assertEqual(
asset.rec_name, 'Product 1 | 2.8000 usd/u | 05/02/2022')
# run worker
self.prep_valstore_run_worker()
values = ValStore.search([
('cashbook', '=', book.id)], order=[('field_name', 'ASC')])
self.assertEqual(len(values), len(Book.valuestore_fields()))
self.assertEqual(
values[0].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance|2.50|2')
self.assertEqual(
values[1].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance_all|2.50|2')
self.assertEqual(
values[2].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|balance_ref|2.50|2')
self.assertEqual(
values[3].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_rate|2.67|2')
self.assertEqual(
values[4].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_value|4.00|2')
self.assertEqual(
values[5].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|current_value_ref|4.00|2')
self.assertEqual(
values[6].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|diff_amount|1.50|2')
self.assertEqual(
values[7].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|diff_percent|60.00|2')
self.assertEqual(
values[8].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|purchase_amount|2.50|2')
self.assertEqual(
values[9].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|quantity|1.500|3')
self.assertEqual(
values[10].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|quantity_all|1.500|3')
self.assertEqual(
values[11].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_balance|4.00|2')
self.assertEqual(
values[12].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_12m|0.00|2')
self.assertEqual(
values[13].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_total|0.00|2')
self.assertEqual(
values[14].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_12m|0.00|2')
self.assertEqual(
values[15].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_total|0.00|2')
self.assertEqual(
values[16].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales|2.50|2')
self.assertEqual(
values[17].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales_12m|0.00|2')
# end ValueStoreTestCase

View file

@ -152,6 +152,7 @@ class YieldTestCase(object):
self.assertEqual(len(lines), 1)
Line.wfcheck(lines)
self.prep_valstore_run_worker()
self.assertEqual(
lines[0].rec_name,
@ -257,6 +258,7 @@ class YieldTestCase(object):
}])
Line.wfcheck(book_cash.lines)
self.prep_valstore_run_worker()
self.assertEqual(
book_asset.rec_name,
@ -366,6 +368,7 @@ class YieldTestCase(object):
}])
Line.wfcheck(book_asset.lines)
self.prep_valstore_run_worker()
self.assertEqual(
book_asset.rec_name,
@ -451,6 +454,7 @@ class YieldTestCase(object):
self.assertEqual(len(lines), 1)
Line.wfcheck(lines)
self.prep_valstore_run_worker()
self.assertEqual(
lines[0].rec_name,
@ -532,6 +536,7 @@ class YieldTestCase(object):
self.assertEqual(len(lines), 1)
Line.wfcheck(lines)
self.prep_valstore_run_worker()
self.assertEqual(
lines[0].rec_name,
@ -631,6 +636,7 @@ class YieldTestCase(object):
}])
Line.wfcheck(book_cash.lines)
self.prep_valstore_run_worker()
self.assertEqual(
book_asset.rec_name,
@ -743,6 +749,7 @@ class YieldTestCase(object):
}])
Line.wfcheck(book_asset.lines)
self.prep_valstore_run_worker()
self.assertEqual(
book_asset.rec_name,
@ -879,6 +886,7 @@ class YieldTestCase(object):
lines[0].rec_name,
'05/02/2022|Exp/Sp|-23.50 usd|all out (1) [-]|-3.0000 u')
Line.wfcheck(lines)
self.prep_valstore_run_worker()
self.assertEqual(
lines[0].rec_name,
@ -1007,6 +1015,7 @@ class YieldTestCase(object):
self.assertEqual(len(lines), 2)
Line.wfcheck(lines)
self.prep_valstore_run_worker()
self.assertEqual(
lines[0].rec_name,
@ -1150,6 +1159,7 @@ class YieldTestCase(object):
self.assertEqual(len(lines), 1)
Line.wfcheck(lines)
self.prep_valstore_run_worker()
self.assertEqual(
lines[0].rec_name,
@ -1301,6 +1311,7 @@ class YieldTestCase(object):
self.assertEqual(len(lines), 3)
Line.wfcheck(lines)
self.prep_valstore_run_worker()
self.assertEqual(
lines[0].rec_name,
@ -1438,6 +1449,7 @@ class YieldTestCase(object):
self.assertEqual(len(lines), 2)
Line.wfcheck(lines)
self.prep_valstore_run_worker()
self.assertEqual(
lines[0].rec_name,

View file

@ -1,5 +1,5 @@
[tryton]
version=7.0.0
version=7.0.13
depends:
cashbook
investment

26
valuestore.py Normal file
View file

@ -0,0 +1,26 @@
# -*- 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
class ValueStore(metaclass=PoolMeta):
__name__ = 'cashbook.values'
@classmethod
def _maintenance_fields(cls):
""" add fields to update job
"""
result = super(ValueStore, cls)._maintenance_fields()
result.extend([
'quantity', 'current_value', 'current_value_ref',
'diff_amount', 'diff_percent', 'current_rate',
'purchase_amount', 'yield_fee_total', 'yield_dividend_total',
'yield_sales', 'yield_fee_12m', 'yield_dividend_12m',
'yield_sales_12m'])
return result
# end ValueStore

View file

@ -1,2 +1,2 @@
cashbook;7.0.32;7.0.999;mds
cashbook;7.0.33;7.0.999;mds
investment;7.0.26;7.0.999;mds

View file

@ -6,9 +6,18 @@ full copyright notices and license terms. -->
<xpath expr="/tree/field[@name='balance']" position="after">
<field name="current_value" symbol="currency" optional="0"/>
<field name="purchase_amount" symbol="currency" optional="1"/>
<field name="diff_amount" symbol="currency" optional="0"/>
<field name="yield_balance" symbol="currency" optional="1"/>
<field name="diff_percent" optional="0"/>
<field name="quantity" symbol="quantity_uom" optional="0"/>
<field name="quantity_all" symbol="quantity_uom" optional="1"/>
<field name="yield_sales" symbol="currency" optional="1"/>
<field name="yield_sales_12m" symbol="currency" optional="1"/>
<field name="yield_dividend_total" symbol="currency" optional="1"/>
<field name="yield_dividend_12m" symbol="currency" optional="1"/>
<field name="yield_fee_total" symbol="currency" optional="1"/>
<field name="yield_fee_12m" symbol="currency" optional="1"/>
</xpath>
</data>

View file

@ -5,8 +5,19 @@ full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='balance']" position="after">
<field name="current_value" symbol="currency" optional="1"/>
<field name="purchase_amount" symbol="currency" optional="1"/>
<field name="diff_amount" symbol="currency" optional="0"/>
<field name="yield_balance" symbol="currency" optional="1"/>
<field name="diff_percent" optional="0"/>
<field name="quantity" symbol="quantity_uom" optional="1"/>
<field name="quantity_all" symbol="quantity_uom" optional="1"/>
<field name="yield_sales" symbol="currency" optional="1"/>
<field name="yield_sales_12m" symbol="currency" optional="1"/>
<field name="yield_dividend_total" symbol="currency" optional="1"/>
<field name="yield_dividend_12m" symbol="currency" optional="1"/>
<field name="yield_fee_total" symbol="currency" optional="1"/>
<field name="yield_fee_12m" symbol="currency" optional="1"/>
</xpath>
</data>