Compare commits

..

69 commits

Author SHA1 Message Date
Frederik Jaeckel
d23c53b047 Version 6.0.12 2023-12-31 13:45:17 +01:00
Frederik Jaeckel
f0072a670c add license 2023-12-31 11:23:22 +01:00
Frederik Jaeckel
86ba1b0bf1 add sorting 2023-12-30 11:44:33 +01:00
Frederik Jaeckel
bd7a41d9fa add update of cashbooks on update of asset-rates 2023-12-30 10:57:17 +01:00
Frederik Jaeckel
114c6d1f9b cashbook: optimize for speed for checking rows 2023-12-29 23:09:00 +01:00
Frederik Jaeckel
e16717959b add worker-based precalculation of cashbook-values 2023-12-29 23:07:39 +01:00
Frederik Jaeckel
0761d71e29 remove caching 2023-12-23 10:44:55 +01:00
Frederik Jaeckel
b3733c5c7f fix DEF_NONE 2023-12-06 22:06:18 +01:00
Frederik Jaeckel
428ffb20b5 Etikett ver 6.0.11 zum Änderungssatz c87683b82288 hinzugefügt 2023-12-06 21:59:15 +01:00
Frederik Jaeckel
186b64e4b9 Version 6.0.11 2023-12-06 21:58:58 +01:00
Frederik Jaeckel
f3f0508821 tests: formatting 2023-12-03 17:37:43 +01:00
Frederik Jaeckel
cce59eb8bf formatting 2023-12-03 17:31:42 +01:00
Frederik Jaeckel
a7dda40f43 Etikett ver 6.0.10 zum Änderungssatz 2c7377b88a5a hinzugefügt 2023-06-08 17:18:58 +02:00
Frederik Jaeckel
0cc4ce05f1 Version 6.0.10 2023-06-08 17:18:43 +02:00
Frederik Jaeckel
3793efc161 tests: add company to context 2023-06-08 16:00:36 +02:00
Frederik Jaeckel
6495e0317e tests: formatting 2023-06-08 14:34:56 +02:00
Frederik Jaeckel
b84d7ea0fb formatting 2023-06-08 14:00:59 +02:00
Frederik Jaeckel
177dec2d7d Etikett ver 6.0.9 zum Änderungssatz 783aaee66f11 hinzugefügt 2023-04-19 09:45:04 +02:00
Frederik Jaeckel
4620f5aad2 Version 6.0.9 2023-04-19 09:44:56 +02:00
Frederik Jaeckel
7c67fb6de7 line: formatting, fix - on_change_with_quantity_digits() 2023-04-19 09:43:29 +02:00
Frederik Jaeckel
38e9477286 Etikett ver 6.0.8 zum Änderungssatz db9ce46e07e5 hinzugefügt 2023-04-17 12:03:36 +02:00
Frederik Jaeckel
dcb746a56b Version 6.0.8 2023-04-17 12:03:26 +02:00
Frederik Jaeckel
0332dd807e line: selection of digits for quantity 2023-04-17 12:01:51 +02:00
Frederik Jaeckel
a9b8f5552c Etikett ver 6.0.7 zum Änderungssatz 2f73b961caf1 hinzugefügt 2023-03-05 10:30:38 +01:00
Frederik Jaeckel
882b8d2025 Version 6.0.7 2023-03-05 10:30:30 +01:00
Frederik Jaeckel
20c3cd5ed5 remove logging, add trytond.conf-settings 2023-03-05 10:26:39 +01:00
Frederik Jaeckel
6c5be8df2d book: optimize query for speed 2023-03-04 21:21:54 +01:00
Frederik Jaeckel
e6bb17f517 readme 2023-02-28 09:22:09 +01:00
Frederik Jaeckel
19e4a26676 fix: import + no symbol if None 2023-02-27 21:17:48 +01:00
Frederik Jaeckel
3512e87f71 Etikett ver 6.0.6 zum Änderungssatz 3f4bf4551378 hinzugefügt 2023-02-27 20:50:28 +01:00
Frederik Jaeckel
f0114b6f09 Version 6.0.6 2023-02-27 20:50:19 +01:00
Frederik Jaeckel
1e1e7d6b85 book:caching for line, settings: cache clear 2023-02-27 20:46:41 +01:00
Frederik Jaeckel
2b9a2ba07a book: add cache for asset-rates 2023-02-27 10:20:23 +01:00
Frederik Jaeckel
009f44816e book: new field 'purchase_amount', optimize form
speedup: indexes, caching
2023-02-26 22:51:24 +01:00
Frederik Jaeckel
d6ddb7a7d7 line: fix exception if missing config; book: optimize form 2023-02-23 10:35:30 +01:00
Frederik Jaeckel
e364560d0a book: optimized field 'yield_balance' 2023-02-22 21:24:58 +01:00
Frederik Jaeckel
8e5a730b36 book: added fields to book-form 2023-02-22 20:33:12 +01:00
Frederik Jaeckel
56961d2ea5 cashbook: yield-info prepared 2023-02-22 16:21:23 +01:00
Frederik Jaeckel
83950fc23a line: add help, fix form 2023-02-21 22:36:20 +01:00
Frederik Jaeckel
f9892379b1 line: tests... ok 2023-02-21 22:22:23 +01:00
Frederik Jaeckel
242f6d9578 line: field 'trade_fee' ok + test 2023-02-21 12:57:10 +01:00
Frederik Jaeckel
2176b84d52 line: fee tests ergänzt 2023-02-20 23:22:31 +01:00
Frederik Jaeckel
4e118afffb line: field 'asset_gainloss' ok + test 2023-02-18 20:55:04 +01:00
Frederik Jaeckel
6ab88d9fb5 line: gain/loss ok + test 2023-02-17 10:20:06 +01:00
Frederik Jaeckel
32eac5aa6c line: gain/loss field ... 2023-02-16 23:12:48 +01:00
Frederik Jaeckel
a47057900a line: updated get_gainloss_data_sql + todos 2023-02-16 16:59:50 +01:00
Frederik Jaeckel
9287db67ed add: field 'asset_gainloss' + searcher + test +todos 2023-02-15 22:34:52 +01:00
Frederik Jaeckel
5aad26da71 add: query for gain/loss 2023-02-14 23:03:12 +01:00
Frederik Jaeckel
71cdadb8ad line: negate amount if splitline=spout - tests 2023-02-14 22:27:25 +01:00
Frederik Jaeckel
d820fc7109 field trade_fee + asset_dividend ok + searcher + test 2023-02-12 22:01:07 +01:00
Frederik Jaeckel
c70d2fef7a line: add fields 'Fee' + 'Dividend' - todos 2023-02-12 00:09:56 +01:00
Frederik Jaeckel
43c9a1a2fa Etikett ver 6.0.5 zum Änderungssatz f0356df3abb0 hinzugefügt 2023-02-05 18:10:07 +01:00
Frederik Jaeckel
a7a9f9ef3d Version 6.0.5 2023-02-05 18:10:00 +01:00
Frederik Jaeckel
85d385901f line: fix write() - get 'bookingtype' from line if not in values 2023-02-05 11:35:55 +01:00
Frederik Jaeckel
cb81f788d6 Etikett ver 6.0.4 zum Änderungssatz 96f6e52d1e14 hinzugefügt 2023-02-01 14:51:54 +01:00
Frederik Jaeckel
e65c961e61 Version 6.0.4 2023-02-01 14:51:47 +01:00
Frederik Jaeckel
e8d69b64ae line/splitline: fixed selection of quantity-uom/digits 2023-02-01 14:29:48 +01:00
Frederik Jaeckel
6b630b7c20 Etikett ver 6.0.3 zum Änderungssatz 62e4472ad4a2 hinzugefügt 2023-01-30 09:27:52 +01:00
Frederik Jaeckel
9f12861b79 Version 6.0.3 2023-01-30 09:27:44 +01:00
Frederik Jaeckel
934d0fb207 reconciliation: use 'quantity_digits' for digits of start/end-quantity 2023-01-30 09:25:44 +01:00
Frederik Jaeckel
9edd2d4a95 line: add performance values to line-form 2023-01-29 23:16:22 +01:00
Frederik Jaeckel
3243fbf844 Etikett ver 6.0.2 zum Änderungssatz ae7678260358 hinzugefügt 2023-01-28 13:13:20 +01:00
Frederik Jaeckel
c9d6bf21a5 Version 6.0.2 2023-01-28 13:13:14 +01:00
Frederik Jaeckel
a315f4e768 cashbook: view current_value/-ref on chasbooks with btype=None if
asset-cashbooks are below
2023-01-28 13:03:24 +01:00
Frederik Jaeckel
674f72476e book: asset-query ausgelagert 2023-01-24 21:25:29 +01:00
Frederik Jaeckel
12e088f79a line: fix transfer between cash-/asset-book with zero quantity 2023-01-23 22:29:41 +01:00
Frederik Jaeckel
bbf94c95df line: fix rec_name 2023-01-22 10:28:09 +01:00
Frederik Jaeckel
29b74d0600 Etikett ver 6.0.1 zum Änderungssatz 67d3f883961c hinzugefügt 2023-01-21 19:18:44 +01:00
Frederik Jaeckel
269e744b8f Version 6.0.1 2023-01-21 19:18:36 +01:00
14 changed files with 238 additions and 363 deletions

View file

@ -9,7 +9,7 @@ pip install mds-cashbook-investment
Requires
========
- Tryton 7.0
- Tryton 6.0
How to
======
@ -23,6 +23,59 @@ You can monitor trading fees, dividends and sales profits.
Changes
=======
*7.0.0 - 06.12.2023*
*6.0.12 - 31.12.2023*
- compatibility to Tryton 7.0
- remove caching
- add worker-based precalculation of cashbook-values
*6.0.11 - 06.12.2023*
- code optimized
*6.0.10 - 08.06.2023*
- code optimized
*6.0.9 - 19.04.2023*
- fix: line - exception if add split-lines
*6.0.8 - 17.04.2023*
- fix: line - selection of digits for quantity
*6.0.7 - 05.03.2023*
- updt: optimize queries for speed, optimize caching
- add: trytond.conf-settings
*6.0.6 - 27.02.2023*
- add: caching
- add: performance and yield info
*6.0.5 - 05.02.2023*
- fix: line rewrite values
*6.0.4 - 01.02.2023*
- fix: selection of quantity-uom/digits on line/spitline
*6.0.3 - 30.01.2023*
- add: performance-tab to line-form
- fix: digits of start/end-quantity in reconciliation
*6.0.2 - 28.01.2023*
- fix: transfer between cash-/asset-book with zero quantity
- add: view value/percent on chasbooks with btype=None
*6.0.1 - 21.01.2023*
- works
*6.0.0 - 20.12.2022*
- init

368
book.py
View file

@ -3,7 +3,7 @@
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
from trytond.model import fields, SymbolMixin, Index
from trytond.model import fields, SymbolMixin
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Or, Bool, If
from trytond.modules.cashbook.book import STATES2, DEPENDS2
@ -25,7 +25,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
__name__ = 'cashbook.book'
asset = fields.Many2One(
string='Asset',
string='Asset', select=True,
model_name='investment.asset', ondelete='RESTRICT',
states={
'required': Eval('feature', '') == 'asset',
@ -51,7 +51,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
model_name='product.uom.category',
states={'invisible': True}), 'on_change_with_asset_uomcat')
quantity_uom = fields.Many2One(
string='UOM',
string='UOM', select=True,
model_name='product.uom', ondelete='RESTRICT',
domain=[('category.id', '=', Eval('asset_uomcat', -1))],
states={
@ -127,9 +127,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
string='Purchase Amount',
help='Total purchase amount, from shares and fees.',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': ~Or(
Eval('feature', '') == 'asset',
~Bool(Eval('feature')))},
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']),
'get_asset_quantity', searcher='search_asset_quantity')
@ -179,20 +177,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']),
'get_yield_balance_data', searcher='search_asset_quantity')
@classmethod
def __setup__(cls):
super(Book, cls).__setup__()
t = cls.__table__()
cls._sql_indexes.update({
Index(
t,
(t.asset, Index.Equality())),
Index(
t,
(t.quantity_uom, Index.Equality())),
})
'on_change_with_yield_balance', searcher='search_asset_quantity')
@classmethod
def view_attributes(cls):
@ -333,39 +318,15 @@ class Book(SymbolMixin, metaclass=PoolMeta):
"""
return 4
@classmethod
def get_yield_balance_data(cls, cashbooks, names):
@fields.depends('yield_sales', 'yield_dividend_total', 'diff_amount')
def on_change_with_yield_balance(self, name=None):
""" 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 = [
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])
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
sum_lst = [
self.diff_amount, self.yield_dividend_total, self.yield_sales]
sum2 = sum([x for x in sum_lst if x is not None])
return sum2
@classmethod
def get_yield_data_sql(cls, date_from=None, date_to=None):
@ -557,83 +518,19 @@ class Book(SymbolMixin, metaclass=PoolMeta):
where=(tab_type.feature == 'asset'))
return (query, tab_book)
@classmethod
def get_asset_amounts_sub_sql(cls):
""" get table of asset and its values for
subordered cashbooks
"""
(tab_quantity, tab_book) = cls.get_asset_quantity_sql()
tab_subids = sub_ids_hierarchical('cashbook.book')
query = tab_book.join(
tab_subids,
condition=tab_book.id == tab_subids.parent,
).join(
tab_quantity,
condition=tab_quantity.id == AnyInArray(tab_subids.subids),
).select(
tab_book.id,
tab_quantity.id.as_('id_subbook'),
tab_quantity.quantity,
tab_quantity.quantity_all,
tab_quantity.rate,
tab_quantity.currency,
tab_quantity.currency_digits,
tab_quantity.asset_currency,
tab_quantity.purchase_amount,
tab_quantity.quantity_uom.as_('book_uom'),
tab_quantity.uom.as_('asset_uom'))
return (query, tab_book)
@classmethod
def get_generic_amounts_sub_sql(cls):
""" query to get amounts of current and subordered
non-asset cashbooks grouped by currency
"""
pool = Pool()
BType = pool.get('cashbook.type')
tab_btype = BType.__table__()
tab_book1 = cls.__table__()
tab_book2 = cls.__table__()
subids_book = sub_ids_hierarchical('cashbook.book')
(query_amounts, tab_line) = cls.get_balance_of_cashbook_sql()
query = tab_book1.join(
subids_book,
condition=subids_book.parent == tab_book1.id,
).join(
tab_book2,
condition=tab_book2.id == AnyInArray(subids_book.subids),
).join(
tab_btype,
condition=(
tab_btype.id == tab_book2.btype) & (
tab_btype.feature != 'asset'),
).join(
query_amounts,
condition=query_amounts.cashbook == tab_book2.id,
).select(
tab_book1.id,
Sum(query_amounts.balance).as_('balance'),
Sum(query_amounts.balance_all).as_('balance_all'),
query_amounts.currency,
group_by=[tab_book1.id, query_amounts.currency])
return (query, tab_book1)
@classmethod
def get_asset_quantity_values(cls, cashbooks, names):
""" get quantities
field: quantity, quantity_all, current_value,
current_value_ref, diff_amount, diff_percent,
current_rate, purchase_amount,
include subordered cashbooks for cashbooks w/o btype
current_rate, purchase_amount
"""
pool = Pool()
CBook = pool.get('cashbook.book')
Uom = pool.get('product.uom')
Currency = pool.get('currency.currency')
cursor = Transaction().connection.cursor()
(query, tab_book) = cls.get_asset_quantity_sql()
company_currency = CBook.default_currency()
result = {
@ -641,187 +538,157 @@ class Book(SymbolMixin, metaclass=PoolMeta):
for x in [
'quantity', 'quantity_all', 'current_value',
'current_value_ref', 'diff_amount', 'diff_percent',
'current_rate', 'purchase_amount', 'digits']
'current_rate', 'purchase_amount', 'purchase_amount_ref',
'digits']
}
def values_from_record(rdata):
""" compute values for record
"""
# uom-factor
if rdata['asset_uom'] == rdata['book_uom']:
if rdata[6] == rdata[7]:
uom_factor = Decimal('1.0')
else:
uom_factor = Decimal(
Uom.compute_qty(
Uom(rdata['asset_uom']), 1.0,
Uom(rdata['book_uom']), round=False))
Uom(rdata[6]), 1.0,
Uom(rdata[7]), round=False))
current_value = Currency.compute(
rdata['asset_currency'],
rdata['rate'] * rdata['quantity'] / uom_factor,
rdata['book_currency'])
return (rdata['id'], {
'quantity': rdata['quantity'],
'quantity_all': rdata['quantity_all'],
rdata[8],
rdata[3] * rdata[1] / uom_factor,
rdata[4])
return (record[0], {
'quantity': rdata[1],
'quantity_all': rdata[2],
'current_value': current_value,
'current_value_ref': Currency.compute(
rdata['asset_currency'],
rdata['rate'] * rdata['quantity'] / uom_factor,
rdata[8],
rdata[3] * rdata[1] / uom_factor,
company_currency
if company_currency is not None
else rdata['asset_currency']),
'diff_amount': current_value - rdata['purchase_amount'],
if company_currency is not None else rdata[8]),
'diff_amount': current_value - rdata[9],
'diff_percent': (
Decimal('100.0') * current_value /
rdata['purchase_amount'] - Decimal('100.0')
).quantize(Decimal(str(1/10**rdata['digits'])))
if rdata['purchase_amount'] != Decimal('0.0') else None,
rdata[9] - Decimal('100.0')
).quantize(Decimal(str(1/10**rdata[5])))
if rdata[9] != Decimal('0.0') else None,
'current_rate': (
current_value / rdata['quantity']
).quantize(Decimal(str(1/10**rdata['digits'])))
if rdata['quantity'] != Decimal('0.0') else None,
'purchase_amount': rdata['purchase_amount'].quantize(
Decimal(str(1/10**rdata['digits']))),
current_value / rdata[1]
).quantize(Decimal(str(1/10**rdata[5])))
if rdata[1] != Decimal('0.0') else None,
'purchase_amount': record[9].quantize(
Decimal(str(1/10**rdata[5]))),
'purchase_amount_ref': Currency.compute(
rdata[4],
record[9],
company_currency
if company_currency is not None else rdata[4]),
})
view_cashbook_ids = list({
x.id for x in cashbooks if x.feature is None})
asset_cashbook_ids = list({
x.id for x in cashbooks if x.feature == 'asset'})
generic_cashbooks = list({
x for x in cashbooks if x.feature == 'gen'})
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)
# check skipped cashbooks
assert list({
x.id
for x in cashbooks
if x.feature not in ['asset', 'gen', None]
}) == [], 'unknown feature of cashbook'
# get values of asset-cashbooks in 'cashbooks' of type=asset,
# values of current cashbook
if asset_cashbook_ids:
(query, tab_book) = cls.get_asset_quantity_sql()
query.where &= tab_book.id.in_(asset_cashbook_ids)
# get values of asset-cashbooks in 'cashbooks' of type=asset
if len(ids_assetbooks) > 0:
query.where &= tab_book.id.in_(ids_assetbooks)
cursor.execute(*query)
records = cursor.fetchall()
for record in records:
(book_id, values) = values_from_record({
'id': record[0],
'quantity': record[1],
'quantity_all': record[2],
'rate': record[3],
'book_currency': record[4],
'digits': record[5],
'asset_uom': record[6],
'book_uom': record[7],
'asset_currency': record[8],
'purchase_amount': record[9]})
(book_id, values) = values_from_record(record)
for name in values.keys():
result[name][book_id] = values[name]
enable_byfields = set({
# add aggregated values of cashbooks without type
aggr_names = [
'current_value', 'current_value_ref',
'purchase_amount'}).intersection(set(names))
'diff_amount', 'diff_percent']
queried_names = list(set(aggr_names).intersection(set(names)))
# add values of current generic-cashbooks
if generic_cashbooks and enable_byfields:
fnames = [
('current_value', 'balance'),
('current_value_ref', 'balance_ref'),
('purchase_amount', 'balance')]
for generic_cashbook in generic_cashbooks:
for fname in fnames:
(fn_to, fn_from) = fname
if fn_to in names:
result[fn_to][generic_cashbook.id] = getattr(
generic_cashbook, fn_from)
if (len(queried_names) > 0) and (len(ids_nonebtypes) > 0):
# query all subordered asset-cashbooks to get values for
# cashbooks without type
# add amounts of non-asset cashbooks,
if view_cashbook_ids and enable_byfields:
# sum amounts of subordered generic-cashbooks
(query_nonasset, tab_book) = cls.get_generic_amounts_sub_sql()
query_nonasset.where = tab_book.id.in_(view_cashbook_ids)
cursor.execute(*query_nonasset)
(tab_quantity, tab_book) = cls.get_asset_quantity_sql()
tab_subids = sub_ids_hierarchical('cashbook.book')
query = tab_book.join(
tab_subids,
condition=tab_book.id == tab_subids.parent,
).join(
tab_quantity,
condition=tab_quantity.id == AnyInArray(tab_subids.subids),
).select(
tab_book.id,
Sum(tab_quantity.quantity), # 1
Sum(tab_quantity.quantity_all), # 2
tab_quantity.rate, # 3
tab_quantity.currency, # 4
tab_quantity.currency_digits, # 5
tab_quantity.uom, # 6
tab_quantity.quantity_uom, # 7
tab_quantity.asset_currency, # 8
Sum(tab_quantity.purchase_amount), # 9
tab_book.currency.as_('currency_book'), # 10
where=tab_book.id.in_(ids_nonebtypes),
group_by=[
tab_book.id, tab_quantity.rate,
tab_quantity.currency, tab_quantity.currency_digits,
tab_quantity.uom, tab_quantity.quantity_uom,
tab_quantity.asset_currency, tab_book.currency])
cursor.execute(*query)
records = cursor.fetchall()
for record in records:
cbook = CBook(record[0])
rdata = {
'id': record[0],
'quantity': Decimal('1.0'),
'quantity_all': None,
'rate': record[1], # balance
'book_currency': cbook.currency.id,
'digits': cbook.currency.digits,
'asset_uom': 0,
'book_uom': 0,
'asset_currency': record[3],
'purchase_amount': record[1]}
(book_id, values) = values_from_record(rdata)
(book_id, values) = values_from_record(record)
for name in [
('current_value', 'current_value'),
('current_value_ref', 'current_value_ref'),
('purchase_amount', 'current_value')]:
(fn_to, fn_from) = name
if fn_to in names:
if result[fn_to][book_id] is None:
result[fn_to][book_id] = Decimal('0.0')
result[fn_to][book_id] += values[fn_from]
# sum amounts of subordered asset-cashbooks
(query_subbooks, tab_book) = cls.get_asset_amounts_sub_sql()
query_subbooks.where = tab_book.id.in_(view_cashbook_ids)
cursor.execute(*query_subbooks)
records = cursor.fetchall()
for record in records:
cbook = CBook(record[0])
(book_id, values) = values_from_record({
'id': record[0],
'quantity': record[2],
'quantity_all': record[3],
'rate': record[4],
'book_currency': record[5],
'digits': record[6],
'asset_uom': record[10],
'book_uom': record[9],
'asset_currency': record[7],
'purchase_amount': record[8]})
for x in ['current_value', 'purchase_amount']:
values[x] = Currency.compute(
record[5], values[x], cbook.currency.id)
for name in [
'current_value', 'current_value_ref',
'purchase_amount']:
'current_value', 'diff_amount',
'current_value_ref', 'purchase_amount_ref']:
if result[name][book_id] is None:
result[name][book_id] = Decimal('0.0')
result[name][book_id] += values[name]
value = Decimal('0.0')
if name == 'current_value':
value = Currency.compute(
company_currency
if company_currency is not None else record[4],
values['current_value_ref'],
record[10])
elif name == 'diff_amount':
value = Currency.compute(
company_currency
if company_currency is not None else record[4],
values['current_value_ref'] -
values['purchase_amount_ref'],
record[10])
elif name in ['current_value_ref', 'purchase_amount_ref']:
value = values[name]
result['digits'][book_id] = record[5]
result[name][book_id] += value
# diff_percent
for id_book in view_cashbook_ids:
c_val = result['current_value'][id_book]
p_amount = result['purchase_amount'][id_book]
digits = result['digits'][id_book] or 2
for id_book in ids_nonebtypes:
c_val = result['current_value_ref'][id_book]
p_amount = result['purchase_amount_ref'][id_book]
digits = result['digits'][id_book]
if (p_amount == Decimal('0.0')) or \
(p_amount is None) or (c_val is None):
continue
result['diff_amount'][id_book] = (
c_val - p_amount).quantize(Decimal(str(1/10 ** digits)))
result['diff_percent'][id_book] = (
Decimal('100.0') * c_val / p_amount - Decimal('100.0')
).quantize(Decimal(str(1/10 ** digits)))
result['digits'][id_book] = None
return {x: result[x] for x in names}
@classmethod
@ -874,8 +741,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'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'])
'yield_fee_12m', 'yield_dividend_12m', 'yield_sales_12m'])
return result
@classmethod
@ -900,10 +766,6 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'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):

View file

@ -14,9 +14,10 @@ from trytond.i18n import gettext
from trytond.report import Report
from trytond.transaction import Transaction
from trytond.modules.cashbook.line import STATES, DEPENDS
from trytond.modules.cashbook.const import DEF_NONE
from .mixin import SecondUomMixin
DEF_NONE = None
STATESQ1 = {
'invisible': And(
Eval('feature', '') != 'asset',

View file

@ -39,7 +39,7 @@ with open(path.join(here, 'versiondep.txt'), encoding='utf-8') as f:
modversion[l2[0]] = {'min': l2[1], 'max': l2[2], 'prefix': l2[3]}
# tryton-version
major_version = 7
major_version = 6
minor_version = 0
requires = []
@ -92,7 +92,6 @@ setup(
'License :: OSI Approved :: GNU General Public License (GPL)',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
],
keywords='tryton cashbook investment',

View file

@ -1,2 +1,17 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import trytond.tests.test_tryton
import unittest
from .test_module import CashbookInvestmentTestCase
__all__ = ['suite']
def suite():
suite = trytond.tests.test_tryton.suite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
CashbookInvestmentTestCase))
return suite

View file

@ -49,7 +49,7 @@ class CbInvTestCase(object):
self.assertEqual(book.show_performance, True)
# run sorter
Book.search(
books = Book.search(
[],
order=[
('current_value', 'ASC'),
@ -103,12 +103,6 @@ class CbInvTestCase(object):
asset.rec_name, 'Product 1 | 12.5000 usd/u | 05/02/2022')
(usd, euro) = self.prep_2nd_currency(company)
self.assertEqual(len(usd.rates), 1)
self.assertEqual(usd.rates[0].rate, Decimal('1.05'))
self.assertEqual(usd.rates[0].date, date(2022, 5, 2))
self.assertEqual(euro.rates[0].rate, Decimal('1.0'))
self.assertEqual(euro.rates[0].date, date(2022, 5, 2))
self.assertEqual(company.currency.rec_name, 'Euro')
BType.write(*[
@ -188,35 +182,26 @@ class CbInvTestCase(object):
}])],
}])],
}])
self.prep_valstore_run_worker()
self.assertEqual(len(books), 1)
self.assertEqual(books[0].rec_name, 'L0-Euro-None')
self.assertEqual(books[0].balance, Decimal('58.57'))
self.assertEqual(books[0].balance_ref, Decimal('58.57'))
# balance of asset-books: 29,286 €
# value of asset-books: 11.9€ + 12.5USD/1.05 = 23.8€
# current_value:
# +15€ (15.00€ - L1-Euro-Cash)
# +15$ / 1.05 (14.29€ - L1-USD-Cash)
# +12.5$/1.05 (11.90€ - L1-Euro-Depot)
# +12.5$/1.05 (11.90€ - L1-USD-Depot)
# = 53.09€
self.assertEqual(books[0].current_value, Decimal('53.09'))
self.assertEqual(books[0].current_value_ref, Decimal('53.09'))
self.assertEqual(books[0].purchase_amount, Decimal('58.58'))
self.assertEqual(books[0].current_value, Decimal('23.8'))
self.assertEqual(books[0].current_value_ref, Decimal('23.8'))
self.assertEqual(books[0].diff_amount, Decimal('-5.49'))
self.assertEqual(books[0].diff_percent, Decimal('-9.37'))
self.assertEqual(books[0].diff_percent, Decimal('-18.74'))
# searcher
self.assertEqual(Book.search_count([
('current_value', '=', Decimal('53.09'))]), 1)
('current_value', '=', Decimal('23.8'))]), 1)
self.assertEqual(Book.search_count([
('current_value_ref', '=', Decimal('53.09'))]), 1)
('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('-9.37'))]), 1)
('diff_percent', '=', Decimal('-18.74'))]), 1)
self.assertEqual(Book.search_count([
('quantity', '=', Decimal('1.0'))]), 2)
self.assertEqual(Book.search_count([
@ -224,17 +209,15 @@ class CbInvTestCase(object):
self.assertEqual(Book.search_count([
('current_rate', '=', Decimal('11.9'))]), 1)
self.assertEqual(Book.search_count([
('purchase_amount', '=', Decimal('15.0'))]), 4)
('purchase_amount', '=', Decimal('15.0'))]), 2)
self.assertEqual(len(books[0].childs), 4)
self.assertEqual(
books[0].childs[0].rec_name,
'L0-Euro-None/L1-Euro-Cash | 15.00 € | Open')
self.assertEqual(
books[0].childs[0].current_value, Decimal('15.0'))
self.assertEqual(
books[0].childs[0].current_value_ref, Decimal('15.0'))
self.assertEqual(books[0].childs[0].current_value, None)
self.assertEqual(books[0].childs[0].current_value_ref, None)
self.assertEqual(books[0].childs[0].diff_amount, None)
self.assertEqual(books[0].childs[0].diff_percent, None)
@ -244,7 +227,6 @@ class CbInvTestCase(object):
self.assertEqual(
books[0].childs[1].asset.rec_name,
'Product 1 | 12.5000 usd/u | 05/02/2022')
# asset: usd, rate 12.50 usd/u @ 2022-05-02
self.assertEqual(
books[0].childs[1].current_value, Decimal('11.9'))
self.assertEqual(
@ -257,10 +239,8 @@ class CbInvTestCase(object):
self.assertEqual(
books[0].childs[2].rec_name,
'L0-Euro-None/L1-USD-Cash | 15.00 usd | Open')
self.assertEqual(
books[0].childs[2].current_value, Decimal('15.0'))
self.assertEqual(
books[0].childs[2].current_value_ref, Decimal('14.29'))
self.assertEqual(books[0].childs[2].current_value, None)
self.assertEqual(books[0].childs[2].current_value_ref, None)
self.assertEqual(books[0].childs[2].diff_amount, None)
self.assertEqual(books[0].childs[2].diff_percent, None)
@ -828,8 +808,7 @@ class CbInvTestCase(object):
self.assertRaisesRegex(
UserError,
'A value is required for field "Asset" in ' +
'"Book 1 | 0.00 usd | Open | 0.0000 u" of "Cashbook".',
'A value is required for field "Asset" in "Cashbook".',
Book.write,
*[
[book],

View file

@ -132,24 +132,21 @@ class ValueStoreTestCase(object):
'[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,
values[12].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_total|0.00|2')
self.assertEqual(
values[14].rec_name,
values[13].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_12m|0.00|2')
self.assertEqual(
values[15].rec_name,
values[14].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_total|0.00|2')
self.assertEqual(
values[16].rec_name,
values[15].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales|2.50|2')
self.assertEqual(
values[17].rec_name,
values[16].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales_12m|0.00|2')
# add rate
@ -206,24 +203,21 @@ class ValueStoreTestCase(object):
'[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,
values[12].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_total|0.00|2')
self.assertEqual(
values[14].rec_name,
values[13].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_12m|0.00|2')
self.assertEqual(
values[15].rec_name,
values[14].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_total|0.00|2')
self.assertEqual(
values[16].rec_name,
values[15].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales|2.50|2')
self.assertEqual(
values[17].rec_name,
values[16].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales_12m|0.00|2')
# update rate
@ -281,24 +275,21 @@ class ValueStoreTestCase(object):
'[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,
values[12].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_total|0.00|2')
self.assertEqual(
values[14].rec_name,
values[13].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_12m|0.00|2')
self.assertEqual(
values[15].rec_name,
values[14].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_total|0.00|2')
self.assertEqual(
values[16].rec_name,
values[15].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales|2.50|2')
self.assertEqual(
values[17].rec_name,
values[16].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales_12m|0.00|2')
# delete rate
@ -354,24 +345,21 @@ class ValueStoreTestCase(object):
'[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,
values[12].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_dividend_total|0.00|2')
self.assertEqual(
values[14].rec_name,
values[13].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_12m|0.00|2')
self.assertEqual(
values[15].rec_name,
values[14].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_fee_total|0.00|2')
self.assertEqual(
values[16].rec_name,
values[15].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales|2.50|2')
self.assertEqual(
values[17].rec_name,
values[16].rec_name,
'[Book 1 | 2.50 € | Open | 1.500 u]|yield_sales_12m|0.00|2')
# end ValueStoreTestCase

View file

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

View file

@ -1,2 +1,2 @@
cashbook;7.0.32;7.0.999;mds
investment;7.0.26;7.0.999;mds
cashbook;6.0.31;6.0.999;mds
investment;6.0.25;6.0.999;mds

View file

@ -5,20 +5,10 @@ full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='balance']" position="after">
<field name="current_value" symbol="currency" optional="0"/>
<field name="current_value_ref" symbol="company_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="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"/>
<field name="current_value" symbol="currency"/>
<field name="diff_amount" symbol="currency"/>
<field name="diff_percent"/>
<field name="quantity" symbol="quantity_uom"/>
</xpath>
</data>

View file

@ -5,20 +5,8 @@ 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="current_value_ref" symbol="company_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"/>
<field name="diff_amount" symbol="currency"/>
<field name="diff_percent"/>
</xpath>
</data>

View file

@ -5,9 +5,9 @@ full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='balance']" position="after">
<field name="quantity_credit" optional="0"/>
<field name="quantity_debit" optional="0"/>
<field name="quantity_balance" optional="0"/>
<field name="quantity_credit"/>
<field name="quantity_debit"/>
<field name="quantity_balance"/>
</xpath>
</data>

View file

@ -5,7 +5,7 @@ full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='end_amount']" position="after">
<field name="start_quantity" optional="0"/>
<field name="end_quantity" optional="0"/>
<field name="start_quantity"/>
<field name="end_quantity"/>
</xpath>
</data>

View file

@ -5,8 +5,8 @@ full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='amount_2nd_currency']" position="after">
<field name="quantity" symbol="quantity_uom" optional="0"/>
<field name="quantity_2nd_uom" symbol="quantity2nd" optional="0"/>
<field name="quantity" symbol="quantity_uom"/>
<field name="quantity_2nd_uom" symbol="quantity2nd"/>
</xpath>
</data>