cashbook_investment/book.py

688 lines
28 KiB
Python
Raw Normal View History

2022-12-21 23:32:26 +00:00
# -*- 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.
2023-06-08 15:13:40 +00:00
from trytond.model import fields, SymbolMixin, Index
2022-12-22 23:34:45 +00:00
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Or, Len, Bool, If
2022-12-21 23:32:26 +00:00
from trytond.modules.cashbook.book import STATES2, DEPENDS2
2022-12-22 23:34:45 +00:00
from trytond.transaction import Transaction
from trytond.report import Report
from trytond.config import config
2022-12-22 23:34:45 +00:00
from decimal import Decimal
from datetime import timedelta
2023-02-22 19:33:12 +00:00
from sql import Literal
2022-12-22 23:34:45 +00:00
from sql.functions import CurrentDate
from sql.aggregate import Sum
from sql.conditionals import Case, Coalesce
2023-03-04 20:21:54 +00:00
from trytond.modules.cashbook.model import sub_ids_hierarchical,\
CACHEKEY_CURRENCY, AnyInArray
2023-02-27 09:20:23 +00:00
from .asset import CACHEKEY_ASSETRATE
2022-12-21 23:32:26 +00:00
# enable/disable caching of cachekey for 'currency.rate'
2023-06-08 12:00:59 +00:00
if config.get(
'cashbook', 'cache_currency',
default='yes').lower() in ['yes', '1', 'true']:
ENA_CURRKEY = True
2023-06-08 12:00:59 +00:00
else:
ENA_CURRKEY = False
# enable/disable caching of cachekey for 'currency.rate'
2023-06-08 12:00:59 +00:00
if config.get(
'cashbook', 'cache_asset',
default='yes').lower() in ['yes', '1', 'true']:
ENA_ASSETKEY = True
2023-06-08 12:00:59 +00:00
else:
ENA_ASSETKEY = False
2023-03-04 20:21:54 +00:00
2022-12-21 23:32:26 +00:00
class Book(SymbolMixin, metaclass=PoolMeta):
2022-12-21 23:32:26 +00:00
__name__ = 'cashbook.book'
2023-06-08 12:00:59 +00:00
asset = fields.Many2One(
2023-06-08 15:13:40 +00:00
string='Asset',
2022-12-21 23:32:26 +00:00
model_name='investment.asset', ondelete='RESTRICT',
states={
'required': Eval('feature', '') == 'asset',
'invisible': Eval('feature', '') != 'asset',
'readonly': Or(
STATES2['readonly'],
2023-12-03 16:31:42 +00:00
Len(Eval('lines')) > 0)},
depends=DEPENDS2+['feature', 'lines'])
2023-06-08 12:00:59 +00:00
quantity_digits = fields.Integer(
string='Digits', help='Quantity Digits',
2022-12-21 23:32:26 +00:00
domain=[
('quantity_digits', '>=', 0),
2023-12-03 16:31:42 +00:00
('quantity_digits', '<=', 6)],
2022-12-21 23:32:26 +00:00
states={
'required': Eval('feature', '') == 'asset',
'invisible': Eval('feature', '') != 'asset',
'readonly': Or(
STATES2['readonly'],
2023-12-03 16:31:42 +00:00
Len(Eval('lines')) > 0)},
depends=DEPENDS2+['feature', 'lines'])
2023-06-08 12:00:59 +00:00
asset_uomcat = fields.Function(fields.Many2One(
string='UOM Category', readonly=True,
model_name='product.uom.category',
2022-12-21 23:32:26 +00:00
states={'invisible': True}), 'on_change_with_asset_uomcat')
2023-06-08 12:00:59 +00:00
quantity_uom = fields.Many2One(
2023-06-08 15:13:40 +00:00
string='UOM',
2022-12-21 23:32:26 +00:00
model_name='product.uom', ondelete='RESTRICT',
2023-12-03 16:31:42 +00:00
domain=[('category.id', '=', Eval('asset_uomcat', -1))],
2022-12-21 23:32:26 +00:00
states={
'required': Eval('feature', '') == 'asset',
'invisible': Eval('feature', '') != 'asset',
'readonly': Or(
2023-12-03 16:31:42 +00:00
STATES2['readonly'],
Len(Eval('lines')) > 0)},
depends=DEPENDS2+['feature', 'lines', 'asset_uomcat'])
2023-06-08 12:00:59 +00:00
symbol = fields.Function(fields.Char(
string='Symbol', readonly=True), 'on_change_with_symbol')
asset_symbol = fields.Function(fields.Many2One(
string='Symbol', readonly=True, model_name='cashbook.book'),
2022-12-25 10:36:12 +00:00
'on_change_with_asset_symbol')
2023-06-08 12:00:59 +00:00
quantity = fields.Function(fields.Numeric(
string='Quantity', help='Quantity of assets until to date',
readonly=True, digits=(16, Eval('quantity_digits', 4)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['quantity_digits', 'feature']), 'get_asset_quantity')
2023-06-08 12:00:59 +00:00
quantity_all = fields.Function(fields.Numeric(
string='Total Quantity', help='Total quantity of all assets',
readonly=True, digits=(16, Eval('quantity_digits', 4)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['quantity_digits', 'feature']), 'get_asset_quantity')
2023-06-08 12:00:59 +00:00
current_value = fields.Function(fields.Numeric(
string='Value',
help='Valuation of the investment based on the current ' +
'stock market price.',
2022-12-22 23:34:45 +00:00
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': ~Eval('show_performance', False)},
depends=['currency_digits', 'show_performance']),
2022-12-22 23:34:45 +00:00
'get_asset_quantity')
2023-06-08 12:00:59 +00:00
current_value_ref = fields.Function(fields.Numeric(
string='Value (Ref.)',
help='Valuation of the investment based on the current stock' +
' exchange price, converted into the company currency.',
2022-12-22 23:34:45 +00:00
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={
'invisible': Or(
2023-12-03 16:31:42 +00:00
~Eval('show_performance', False),
~Bool(Eval('company_currency', -1)))},
depends=['currency_digits', 'show_performance', 'company_currency']),
2022-12-22 23:34:45 +00:00
'get_asset_quantity')
2022-12-21 23:32:26 +00:00
# performance
2023-06-08 12:00:59 +00:00
diff_amount = fields.Function(fields.Numeric(
string='Difference',
help='Difference between acquisition value and current value',
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': ~Eval('show_performance', False)},
depends=['currency_digits', 'show_performance']),
2023-06-08 12:00:59 +00:00
'get_asset_quantity')
diff_percent = fields.Function(fields.Numeric(
string='Percent',
help='percentage performance since acquisition',
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': ~Eval('show_performance', False)},
depends=['currency_digits', 'show_performance']),
2023-06-08 12:00:59 +00:00
'get_asset_quantity')
show_performance = fields.Function(fields.Boolean(
2023-12-03 16:31:42 +00:00
string='Performance', readonly=True), 'on_change_with_show_performance')
2023-06-08 12:00:59 +00:00
current_rate = fields.Function(fields.Numeric(
string='Rate',
help='Rate per unit of investment based on current stock ' +
'exchange price.',
2022-12-24 12:14:51 +00:00
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_asset_quantity')
2023-06-08 12:00:59 +00:00
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)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_asset_quantity')
2023-02-22 15:21:23 +00:00
# yield
2023-06-08 12:00:59 +00:00
yield_dividend_total = fields.Function(fields.Numeric(
string='Dividend', help='Total dividends received',
2023-02-22 15:21:23 +00:00
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
2023-06-08 12:00:59 +00:00
yield_dividend_12m = fields.Function(fields.Numeric(
string='Dividend 1y',
2023-02-22 15:21:23 +00:00
help='Dividends received in the last twelve months',
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
2023-06-08 12:00:59 +00:00
yield_fee_total = fields.Function(fields.Numeric(
string='Trade Fee', help='Total trade fees payed',
2023-02-22 15:21:23 +00:00
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
2023-06-08 12:00:59 +00:00
yield_fee_12m = fields.Function(fields.Numeric(
string='Trade Fee 1y',
2023-02-22 15:21:23 +00:00
help='Trade fees payed in the last twelve month',
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
2023-06-08 12:00:59 +00:00
yield_sales = fields.Function(fields.Numeric(
string='Sales', help='Total profit or loss on sale of shares.',
2023-02-22 15:21:23 +00:00
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
2023-06-08 12:00:59 +00:00
yield_sales_12m = fields.Function(fields.Numeric(
string='Sales 1y',
2023-02-22 15:21:23 +00:00
help='Total profit or loss on sale of shares in the last twelve month.',
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'get_yield_data')
2023-06-08 12:00:59 +00:00
yield_balance = fields.Function(fields.Numeric(
string='Total Yield',
2023-02-22 15:21:23 +00:00
help='Total income: price gain + dividends + sales gains - fees',
readonly=True, digits=(16, Eval('currency_digits', 2)),
2023-12-03 16:31:42 +00:00
states={'invisible': Eval('feature', '') != 'asset'},
depends=['currency_digits', 'feature']), 'on_change_with_yield_balance')
2023-02-22 15:21:23 +00:00
2023-06-08 15:13:40 +00:00
@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())),
})
@classmethod
def view_attributes(cls):
return super(Book, cls).view_attributes() + [
('/tree', 'visual',
2023-12-03 16:31:42 +00:00
If(Eval('show_performance', False),
If(Eval('diff_percent', 0) < 0, 'danger',
2023-06-08 12:00:59 +00:00
If(Eval('diff_percent', 0) > 0,
'success', '')), '')),
]
def get_rec_name(self, name):
""" add quantities - if its a asset-cashbook
"""
recname = super(Book, self).get_rec_name(name)
if self.feature == 'asset':
recname += ' | %(quantity)s %(uom_symbol)s' % {
2023-06-08 12:00:59 +00:00
'quantity': Report.format_number(
self.quantity or 0.0, None,
digits=self.quantity_digits),
'uom_symbol': getattr(self.quantity_uom, 'symbol', '-'),
}
return recname
2022-12-21 23:32:26 +00:00
@fields.depends('asset', 'quantity_uom')
def on_change_asset(self):
""" get uom from asset
"""
if self.asset:
self.quantity_uom = self.asset.uom.id
@classmethod
def default_quantity_digits(cls):
""" default: 4
"""
return 4
@fields.depends('yield_sales', 'yield_dividend_total', 'diff_amount')
2023-02-22 19:33:12 +00:00
def on_change_with_yield_balance(self, name=None):
""" calculate yield total
fee is already contained in 'diff_amount'
2023-02-22 19:33:12 +00:00
"""
2023-06-08 12:00:59 +00:00
sum_lst = [
self.diff_amount, self.yield_dividend_total, self.yield_sales]
2023-02-22 20:24:58 +00:00
sum2 = sum([x for x in sum_lst if x is not None])
return sum2
2023-02-22 19:33:12 +00:00
2023-02-22 15:21:23 +00:00
@classmethod
2023-02-22 19:33:12 +00:00
def get_yield_data_sql(cls, date_from=None, date_to=None):
2023-02-22 15:21:23 +00:00
""" collect yield data
"""
pool = Pool()
Line = pool.get('cashbook.line')
2023-03-04 20:21:54 +00:00
Currency = pool.get('currency.currency')
2023-02-22 15:21:23 +00:00
(tab_line1, tab_line_yield) = Line.get_yield_data_sql()
(tab_line2, tab_line_gainloss) = Line.get_gainloss_data_sql()
tab_book = cls.__table__()
tab_line = Line.__table__()
2023-03-04 20:21:54 +00:00
tab_cur = Currency.__table__()
2023-02-22 15:21:23 +00:00
2023-02-22 19:33:12 +00:00
where = Literal(True)
2023-02-22 15:21:23 +00:00
if date_from:
where &= tab_line.date >= date_from
if date_to:
where &= tab_line.date <= date_to
2023-06-08 12:00:59 +00:00
query = tab_book.join(
tab_line,
condition=tab_line.cashbook == tab_book.id,
).join(
tab_cur,
condition=tab_cur.id == tab_book.currency,
).join(
tab_line_yield,
condition=tab_line_yield.id == tab_line.id,
).join(
tab_line_gainloss,
condition=tab_line_gainloss.id == tab_line.id,
2023-02-22 15:21:23 +00:00
).select(
tab_book.id,
Sum(tab_line_yield.fee).as_('fee'),
Sum(tab_line_yield.dividend).as_('dividend'),
Sum(tab_line_gainloss.gainloss).as_('gainloss'),
2023-03-04 20:21:54 +00:00
tab_cur.digits.as_('currency_digits'),
group_by=[tab_book.id, tab_cur.digits],
2023-12-03 16:31:42 +00:00
where=where)
2023-02-22 15:21:23 +00:00
return (tab_book, query)
@classmethod
def get_yield_data(cls, cashbooks, names):
""" collect yield data
"""
2023-02-22 19:33:12 +00:00
pool = Pool()
IrDate = pool.get('ir.date')
MemCache = pool.get('cashbook.memcache')
2023-02-22 15:21:23 +00:00
cursor = Transaction().connection.cursor()
2023-02-22 19:33:12 +00:00
context = Transaction().context
result = {
2023-06-08 12:00:59 +00:00
x: {y.id: Decimal('0.0') for y in cashbooks}
for x in [
'yield_fee_total', 'yield_dividend_total',
'yield_sales', 'yield_fee_12m', 'yield_dividend_12m',
'yield_sales_12m']}
2023-02-22 15:21:23 +00:00
2023-03-04 20:21:54 +00:00
def quantize_val(value, digits):
2023-02-22 15:21:23 +00:00
""" quantize...
"""
return (
value or Decimal('0.0')
2023-03-04 20:21:54 +00:00
).quantize(Decimal(str(1/10 ** digits)))
2023-02-22 15:21:23 +00:00
2023-02-22 19:33:12 +00:00
query_date = context.get('date', IrDate.today())
cache_keys = {
x.id: MemCache.get_key_by_record(
2023-06-08 12:00:59 +00:00
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)],
2023-06-08 12:00:59 +00:00
'cachekey' if ENA_CURRKEY else 'disabled':
CACHEKEY_CURRENCY % x.currency.id,
}, {
'model': 'investment.rate',
'query': [('asset.id', '=', x.asset.id)],
2023-06-08 12:00:59 +00:00
'cachekey' if ENA_ASSETKEY else 'disabled':
CACHEKEY_ASSETRATE % x.asset.id,
} if x.asset is not None else {}],
2023-06-08 12:00:59 +00:00
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:
(tab_book1, query_total) = cls.get_yield_data_sql()
query_total.where &= tab_book1.id.in_([x.id for x in todo_cashbook])
cursor.execute(*query_total)
records_total = cursor.fetchall()
# results for 12 months
(tab_book2, query_12m) = cls.get_yield_data_sql(
2023-06-08 12:00:59 +00:00
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])
cursor.execute(*query_12m)
records_12m = cursor.fetchall()
2023-02-22 19:33:12 +00:00
for record in records_total:
2023-06-08 12:00:59 +00:00
result['yield_fee_total'][record[0]] = quantize_val(
record[1], record[4])
result['yield_dividend_total'][record[0]] = quantize_val(
record[2], record[4])
result['yield_sales'][record[0]] = quantize_val(
record[3], record[4])
2023-02-22 19:33:12 +00:00
for record in records_12m:
2023-06-08 12:00:59 +00:00
result['yield_fee_12m'][record[0]] = quantize_val(
record[1], record[4])
result['yield_dividend_12m'][record[0]] = quantize_val(
record[2], record[4])
result['yield_sales_12m'][record[0]] = quantize_val(
record[3], record[4])
2023-02-22 15:21:23 +00:00
# store to cache
2023-03-04 20:21:54 +00:00
MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook)
2023-06-08 12:00:59 +00:00
return {x: result[x] for x in names}
2023-02-22 15:21:23 +00:00
2022-12-22 23:34:45 +00:00
@classmethod
2023-01-24 20:25:29 +00:00
def get_asset_quantity_sql(cls):
""" get table of asset and its value, rate, ...
"""
2022-12-22 23:34:45 +00:00
pool = Pool()
CBook = pool.get('cashbook.book')
2022-12-24 12:14:51 +00:00
BookType = pool.get('cashbook.type')
2022-12-22 23:34:45 +00:00
Line = pool.get('cashbook.line')
Asset = pool.get('investment.asset')
Currency = pool.get('currency.currency')
tab_book = CBook.__table__()
2022-12-24 12:14:51 +00:00
tab_type = BookType.__table__()
2022-12-22 23:34:45 +00:00
tab_line = Line.__table__()
tab_cur = Currency.__table__()
tab_asset = Asset.__table__()
(tab_rate, tab2) = Asset.get_rate_data_sql()
(tab_balance, tab2) = CBook.get_balance_of_cashbook_sql()
(tab_line_yield, query_yield) = Line.get_yield_data_sql()
2022-12-22 23:34:45 +00:00
context = Transaction().context
query_date = context.get('qdate', CurrentDate())
2023-06-08 12:00:59 +00:00
query = tab_book.join(
tab_line,
condition=(tab_book.id == tab_line.cashbook),
).join(
tab_type,
condition=tab_book.btype == tab_type.id,
).join(
tab_cur,
condition=tab_book.currency == tab_cur.id,
).join(
tab_asset,
condition=tab_book.asset == tab_asset.id,
).join(
query_yield,
condition=query_yield.id == tab_line.id,
).join(
tab_balance,
condition=tab_book.id == tab_balance.cashbook,
type_='LEFT OUTER',
).join(
tab_rate,
condition=tab_book.asset == tab_rate.id,
type_='LEFT OUTER',
2022-12-22 23:34:45 +00:00
).select(
tab_book.id, # 0
Coalesce(Sum(Case(
(tab_line.date <= query_date,
tab_line.quantity_credit - tab_line.quantity_debit),
2023-06-08 12:00:59 +00:00
else_=Decimal('0.0'),
2022-12-22 23:34:45 +00:00
)), Decimal('0.0')).as_('quantity'), # 1
2023-06-08 12:00:59 +00:00
Sum(
tab_line.quantity_credit -
tab_line.quantity_debit).as_('quantity_all'), # 2
2022-12-22 23:34:45 +00:00
Coalesce(tab_rate.rate, Decimal('0.0')).as_('rate'), # 3
2023-06-08 12:00:59 +00:00
tab_book.currency, # 4
2022-12-22 23:34:45 +00:00
tab_cur.digits.as_('currency_digits'), # 5
tab_asset.uom, # 6
tab_book.quantity_uom, # 7
2023-06-08 12:00:59 +00:00
tab_asset.currency.as_('asset_currency'), # 8
(
Sum(query_yield.fee) + tab_balance.balance
2023-06-08 12:00:59 +00:00
).as_('purchase_amount'), # 9
group_by=[
tab_book.id, tab_rate.rate,
2022-12-22 23:34:45 +00:00
tab_book.currency, tab_cur.digits, tab_asset.uom,
tab_book.quantity_uom, tab_asset.currency,
tab_balance.balance],
2023-12-03 16:31:42 +00:00
where=(tab_type.feature == 'asset'))
2023-01-24 20:25:29 +00:00
return (query, tab_book)
@classmethod
def get_asset_quantity(cls, cashbooks, names):
""" get quantities
2023-03-04 20:21:54 +00:00
field: quantity, quantity_all, current_value,
current_value_ref, diff_amount, diff_percent,
current_rate, purchase_amount
2023-01-24 20:25:29 +00:00
"""
pool = Pool()
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')
2023-01-24 20:25:29 +00:00
cursor = Transaction().connection.cursor()
context = Transaction().context
(query, tab_book) = cls.get_asset_quantity_sql()
company_currency = CBook.default_currency()
2023-03-04 20:21:54 +00:00
result = {
2023-06-08 12:00:59 +00:00
x: {y.id: None for y in cashbooks}
for x in [
'quantity', 'quantity_all', 'current_value',
'current_value_ref', 'diff_amount', 'diff_percent',
'current_rate', 'purchase_amount', 'purchase_amount_ref',
'digits']
2023-03-04 20:21:54 +00:00
}
cache_keys = {
2023-03-04 20:21:54 +00:00
x.id: MemCache.get_key_by_record(
2023-06-08 12:00:59 +00:00
name='get_asset_quantity',
record=x,
query=[{
'model': 'cashbook.line',
'query': [('cashbook.parent', 'child_of', [x.id])],
2023-03-04 20:21:54 +00:00
}, {
2023-06-08 12:00:59 +00:00
'model': 'currency.currency.rate',
'query': [('currency.id', '=', x.currency.id)],
'cachekey' if ENA_CURRKEY else 'disabled':
CACHEKEY_CURRENCY % x.currency.id,
2023-03-04 20:21:54 +00:00
}, {
2023-06-08 12:00:59 +00:00
'model': 'investment.rate',
'query': [('asset.id', '=', x.asset.id)],
'cachekey' if ENA_ASSETKEY else 'disabled':
CACHEKEY_ASSETRATE % x.asset.id,
2023-03-04 20:21:54 +00:00
} 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
"""
2022-12-22 23:34:45 +00:00
# uom-factor
if rdata[6] == rdata[7]:
2022-12-22 23:34:45 +00:00
uom_factor = Decimal('1.0')
2023-06-08 12:00:59 +00:00
else:
2022-12-22 23:34:45 +00:00
uom_factor = Decimal(
2023-06-08 12:00:59 +00:00
Uom.compute_qty(
Uom(rdata[6]), 1.0,
2023-12-03 16:31:42 +00:00
Uom(rdata[7]), round=False))
2022-12-22 23:34:45 +00:00
current_value = Currency.compute(
rdata[8],
rdata[3] * rdata[1] / uom_factor,
2023-12-03 16:31:42 +00:00
rdata[4])
return (record[0], {
'quantity': rdata[1],
'quantity_all': rdata[2],
'current_value': current_value,
2022-12-22 23:34:45 +00:00
'current_value_ref': Currency.compute(
rdata[8],
rdata[3] * rdata[1] / uom_factor,
2023-06-08 12:00:59 +00:00
company_currency
2023-12-03 16:31:42 +00:00
if company_currency is not None else rdata[8]),
2023-03-04 20:21:54 +00:00
'diff_amount': current_value - rdata[9],
'diff_percent': (
2023-06-08 12:00:59 +00:00
Decimal('100.0') * current_value /
2023-03-04 20:21:54 +00:00
rdata[9] - Decimal('100.0')
2023-06-08 12:00:59 +00:00
).quantize(Decimal(str(1/10**rdata[5])))
if rdata[9] != Decimal('0.0') else None,
2022-12-24 12:14:51 +00:00
'current_rate': (
current_value / rdata[1]
2023-06-08 12:00:59 +00:00
).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],
2023-03-04 20:21:54 +00:00
record[9],
2023-06-08 12:00:59 +00:00
company_currency
2023-12-03 16:31:42 +00:00
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]
# 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(record)
for name in values.keys():
result[name][book_id] = values[name]
# add aggregated values of cashbooks without type
2023-06-08 12:00:59 +00:00
aggr_names = [
'current_value', 'current_value_ref',
'diff_amount', 'diff_percent']
queried_names = list(set(aggr_names).intersection(set(names)))
2023-03-04 20:21:54 +00:00
if (len(queried_names) > 0) and (len(ids_nonebtypes) > 0):
# query all subordered asset-cashbooks to get values for
# cashbooks without type
(tab_quantity, tab_book) = cls.get_asset_quantity_sql()
tab_subids = sub_ids_hierarchical('cashbook.book')
2023-06-08 12:00:59 +00:00
query = tab_book.join(
tab_subids,
condition=tab_book.id == tab_subids.parent,
).join(
tab_quantity,
condition=tab_quantity.id == AnyInArray(tab_subids.subids),
2023-03-04 20:21:54 +00:00
).select(
tab_book.id,
2023-06-08 12:00:59 +00:00
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
2023-03-04 20:21:54 +00:00
where=tab_book.id.in_(ids_nonebtypes),
2023-06-08 12:00:59 +00:00
group_by=[
tab_book.id, tab_quantity.rate,
2023-03-04 20:21:54 +00:00
tab_quantity.currency, tab_quantity.currency_digits,
tab_quantity.uom, tab_quantity.quantity_uom,
2023-12-03 16:31:42 +00:00
tab_quantity.asset_currency, tab_book.currency])
cursor.execute(*query)
records = cursor.fetchall()
for record in records:
(book_id, values) = values_from_record(record)
2023-06-08 12:00:59 +00:00
for name in [
'current_value', 'diff_amount',
2023-03-04 20:21:54 +00:00
'current_value_ref', 'purchase_amount_ref']:
if result[name][book_id] is None:
result[name][book_id] = Decimal('0.0')
value = Decimal('0.0')
if name == 'current_value':
value = Currency.compute(
2023-06-08 12:00:59 +00:00
company_currency
if company_currency is not None else record[4],
2023-03-04 20:21:54 +00:00
values['current_value_ref'],
2023-12-03 16:31:42 +00:00
record[10])
2023-03-04 20:21:54 +00:00
elif name == 'diff_amount':
value = Currency.compute(
2023-06-08 12:00:59 +00:00
company_currency
if company_currency is not None else record[4],
values['current_value_ref'] -
values['purchase_amount_ref'],
2023-12-03 16:31:42 +00:00
record[10])
2023-03-04 20:21:54 +00:00
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
2023-03-04 20:21:54 +00:00
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]
2023-06-08 12:00:59 +00:00
if (p_amount == Decimal('0.0')) or \
(p_amount is None) or (c_val is None):
2023-03-04 20:21:54 +00:00
continue
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
# store to cache
2023-03-04 20:21:54 +00:00
MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook)
2023-06-08 12:00:59 +00:00
return {x: result[x] for x in names}
2022-12-22 23:34:45 +00:00
@fields.depends('id')
def on_change_with_show_performance(self, name=None):
""" return True if current or subordered cashbooks
are of type=asset
"""
Book2 = Pool().get('cashbook.book')
if Book2.search_count([
2023-06-08 12:00:59 +00:00
('btype.feature', '=', 'asset'),
('parent', 'child_of', [self.id])]) > 0:
return True
return False
2022-12-25 10:36:12 +00:00
@fields.depends('id')
def on_change_with_asset_symbol(self, name=None):
""" get current cashbook to enable usage of 'symbol'
in the form
"""
return self.id
@fields.depends('quantity_uom', 'currency')
def on_change_with_symbol(self, name=None):
""" get symbol for asset
"""
return '%(currency)s/%(unit)s' % {
'currency': getattr(self.currency, 'symbol', '-'),
2023-12-03 16:31:42 +00:00
'unit': getattr(self.quantity_uom, 'symbol', '-')}
2022-12-21 23:32:26 +00:00
@fields.depends('asset', '_parent_asset.uom')
def on_change_with_asset_uomcat(self, name=None):
""" get uom-category of asset
"""
if self.asset:
return self.asset.uom.category.id
# end Book