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.
|
|
|
|
|
2022-12-22 15:01:10 +00:00
|
|
|
from trytond.model import fields, SymbolMixin
|
2022-12-22 23:34:45 +00:00
|
|
|
from trytond.pool import PoolMeta, Pool
|
2022-12-23 18:15:20 +00:00
|
|
|
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
|
2023-01-15 11:15:54 +00:00
|
|
|
from trytond.report import Report
|
2022-12-22 23:34:45 +00:00
|
|
|
from decimal import Decimal
|
2023-02-22 19:33:12 +00:00
|
|
|
from datetime import timedelta
|
|
|
|
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-02-26 21:51:24 +00:00
|
|
|
from trytond.modules.cashbook.model import CACHEKEY_CURRENCY
|
2023-02-27 09:20:23 +00:00
|
|
|
from .asset import CACHEKEY_ASSETRATE
|
2022-12-21 23:32:26 +00:00
|
|
|
|
|
|
|
|
2022-12-22 15:01:10 +00:00
|
|
|
class Book(SymbolMixin, metaclass=PoolMeta):
|
2022-12-21 23:32:26 +00:00
|
|
|
__name__ = 'cashbook.book'
|
|
|
|
|
2023-02-26 21:51:24 +00:00
|
|
|
asset = fields.Many2One(string='Asset', select=True,
|
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'],
|
|
|
|
Len(Eval('lines')) > 0,
|
|
|
|
),
|
|
|
|
}, depends=DEPENDS2+['feature', 'lines'])
|
|
|
|
quantity_digits = fields.Integer(string='Digits',
|
|
|
|
help='Quantity Digits',
|
|
|
|
domain=[
|
|
|
|
('quantity_digits', '>=', 0),
|
|
|
|
('quantity_digits', '<=', 6),
|
|
|
|
],
|
|
|
|
states={
|
|
|
|
'required': Eval('feature', '') == 'asset',
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
'readonly': Or(
|
|
|
|
STATES2['readonly'],
|
|
|
|
Len(Eval('lines')) > 0,
|
|
|
|
),
|
|
|
|
}, depends=DEPENDS2+['feature', 'lines'])
|
|
|
|
asset_uomcat = fields.Function(fields.Many2One(string='UOM Category',
|
|
|
|
readonly=True, model_name='product.uom.category',
|
|
|
|
states={'invisible': True}), 'on_change_with_asset_uomcat')
|
2023-02-26 21:51:24 +00:00
|
|
|
quantity_uom = fields.Many2One(string='UOM', select=True,
|
2022-12-21 23:32:26 +00:00
|
|
|
model_name='product.uom', ondelete='RESTRICT',
|
|
|
|
domain=[
|
|
|
|
('category.id', '=', Eval('asset_uomcat', -1)),
|
|
|
|
],
|
|
|
|
states={
|
|
|
|
'required': Eval('feature', '') == 'asset',
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
'readonly': Or(
|
|
|
|
STATES2['readonly'],
|
|
|
|
Len(Eval('lines')) > 0,
|
|
|
|
),
|
|
|
|
}, depends=DEPENDS2+['feature', 'lines', 'asset_uomcat'])
|
2022-12-22 15:01:10 +00:00
|
|
|
symbol = fields.Function(fields.Char(string='Symbol', readonly=True),
|
|
|
|
'on_change_with_symbol')
|
2022-12-25 10:36:12 +00:00
|
|
|
asset_symbol = fields.Function(fields.Many2One(string='Symbol',
|
|
|
|
readonly=True, model_name='cashbook.book'),
|
|
|
|
'on_change_with_asset_symbol')
|
2022-12-22 23:34:45 +00:00
|
|
|
quantity = fields.Function(fields.Numeric(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')
|
|
|
|
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')
|
|
|
|
current_value = fields.Function(fields.Numeric(string='Value',
|
2022-12-23 18:15:20 +00:00
|
|
|
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)),
|
|
|
|
states={
|
2023-01-28 12:03:24 +00:00
|
|
|
'invisible': Eval('show_performance', False) == False,
|
|
|
|
}, depends=['currency_digits', 'show_performance']),
|
2022-12-22 23:34:45 +00:00
|
|
|
'get_asset_quantity')
|
|
|
|
current_value_ref = fields.Function(fields.Numeric(string='Value (Ref.)',
|
2022-12-23 18:15:20 +00:00
|
|
|
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={
|
2022-12-23 18:15:20 +00:00
|
|
|
'invisible': Or(
|
2023-01-28 12:03:24 +00:00
|
|
|
Eval('show_performance', False) == False,
|
2022-12-23 18:15:20 +00:00
|
|
|
~Bool(Eval('company_currency', -1)),
|
|
|
|
),
|
2023-01-28 12:03:24 +00:00
|
|
|
}, 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
|
|
|
|
2022-12-23 18:15:20 +00:00
|
|
|
# performance
|
|
|
|
diff_amount = fields.Function(fields.Numeric(string='Difference',
|
|
|
|
help='Difference between acquisition value and current value',
|
|
|
|
readonly=True, digits=(16, Eval('currency_digits', 2)),
|
2022-12-24 12:14:51 +00:00
|
|
|
states={
|
2023-01-28 12:03:24 +00:00
|
|
|
'invisible': Eval('show_performance', False) == False,
|
|
|
|
}, depends=['currency_digits', 'show_performance']), 'get_asset_quantity')
|
2022-12-23 18:15:20 +00:00
|
|
|
diff_percent = fields.Function(fields.Numeric(string='Percent',
|
|
|
|
help='percentage performance since acquisition',
|
|
|
|
readonly=True, digits=(16, Eval('currency_digits', 2)),
|
2022-12-24 12:14:51 +00:00
|
|
|
states={
|
2023-01-28 12:03:24 +00:00
|
|
|
'invisible': Eval('show_performance', False) == False,
|
|
|
|
}, depends=['currency_digits', 'show_performance']), 'get_asset_quantity')
|
|
|
|
show_performance = fields.Function(fields.Boolean(string='Performance',
|
|
|
|
readonly=True), 'on_change_with_show_performance')
|
2022-12-24 12:14:51 +00:00
|
|
|
current_rate = fields.Function(fields.Numeric(string='Rate',
|
|
|
|
help='Rate per unit of investment based on current stock exchange price.',
|
|
|
|
readonly=True, digits=(16, Eval('currency_digits', 2)),
|
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']), 'get_asset_quantity')
|
2023-02-26 21:51:24 +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)),
|
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']),
|
|
|
|
'get_asset_quantity')
|
2022-12-23 18:15:20 +00:00
|
|
|
|
2023-02-22 15:21:23 +00:00
|
|
|
# yield
|
|
|
|
yield_dividend_total = fields.Function(fields.Numeric(string='Dividend',
|
|
|
|
help='Total dividends received',
|
|
|
|
readonly=True, digits=(16, Eval('currency_digits', 2)),
|
2023-02-22 19:33:12 +00:00
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']), 'get_yield_data')
|
2023-02-22 15:21:23 +00:00
|
|
|
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)),
|
2023-02-22 19:33:12 +00:00
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']), 'get_yield_data')
|
2023-02-22 15:21:23 +00:00
|
|
|
yield_fee_total = fields.Function(fields.Numeric(string='Trade Fee',
|
|
|
|
help='Total trade fees payed',
|
|
|
|
readonly=True, digits=(16, Eval('currency_digits', 2)),
|
2023-02-22 19:33:12 +00:00
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']), 'get_yield_data')
|
2023-02-22 15:21:23 +00:00
|
|
|
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)),
|
2023-02-22 19:33:12 +00:00
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']), 'get_yield_data')
|
2023-02-22 15:21:23 +00:00
|
|
|
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)),
|
2023-02-22 19:33:12 +00:00
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']), 'get_yield_data')
|
2023-02-22 15:21:23 +00:00
|
|
|
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)),
|
2023-02-22 19:33:12 +00:00
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']), 'get_yield_data')
|
2023-02-22 15:21:23 +00:00
|
|
|
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)),
|
2023-02-22 19:33:12 +00:00
|
|
|
states={
|
|
|
|
'invisible': Eval('feature', '') != 'asset',
|
|
|
|
}, depends=['currency_digits', 'feature']),
|
|
|
|
'on_change_with_yield_balance')
|
2023-02-22 15:21:23 +00:00
|
|
|
|
2022-12-23 18:15:20 +00:00
|
|
|
@classmethod
|
|
|
|
def view_attributes(cls):
|
|
|
|
return super(Book, cls).view_attributes() + [
|
|
|
|
('/tree', 'visual',
|
2023-01-28 12:03:24 +00:00
|
|
|
If(Eval('show_performance', False) == True,
|
2022-12-23 18:15:20 +00:00
|
|
|
If(Eval('diff_percent', 0) < 0, 'danger',
|
|
|
|
If(Eval('diff_percent', 0) > 0, 'success', '')
|
|
|
|
), '')
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
2023-01-15 11:15:54 +00:00
|
|
|
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' % {
|
|
|
|
'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
|
|
|
|
|
2023-02-26 21:51:24 +00:00
|
|
|
@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
|
2023-02-26 21:51:24 +00:00
|
|
|
fee is already contained in 'diff_amount'
|
2023-02-22 19:33:12 +00:00
|
|
|
"""
|
2023-02-22 20:24:58 +00:00
|
|
|
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
|
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')
|
|
|
|
(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-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
|
|
|
|
|
|
|
|
query = tab_book.join(tab_line,
|
|
|
|
condition=tab_line.cashbook==tab_book.id,
|
|
|
|
).join(tab_line_yield,
|
|
|
|
condition=tab_line_yield.id==tab_line.id,
|
|
|
|
).join(tab_line_gainloss,
|
|
|
|
condition=tab_line_gainloss.id==tab_line.id,
|
|
|
|
).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-02-22 19:33:12 +00:00
|
|
|
group_by=[tab_book.id],
|
|
|
|
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()
|
|
|
|
CashBook = pool.get('cashbook.book')
|
|
|
|
IrDate = pool.get('ir.date')
|
2023-02-26 21:51:24 +00:00
|
|
|
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
|
2023-02-26 21:51:24 +00:00
|
|
|
result = {
|
|
|
|
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
|
|
|
|
|
|
|
def quantize_val(value, line):
|
|
|
|
""" quantize...
|
|
|
|
"""
|
|
|
|
return (
|
|
|
|
value or Decimal('0.0')
|
|
|
|
).quantize(Decimal(str(1/10**line.currency_digits)))
|
|
|
|
|
2023-02-22 19:33:12 +00:00
|
|
|
query_date = context.get('date', IrDate.today())
|
2023-02-26 21:51:24 +00:00
|
|
|
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': CACHEKEY_CURRENCY % x.currency.id,
|
|
|
|
}, {
|
|
|
|
'model': 'investment.rate',
|
|
|
|
'query': [('asset.id', '=', x.asset.id)],
|
2023-02-27 09:20:23 +00:00
|
|
|
'cachekey': CACHEKEY_ASSETRATE % x.asset.id,
|
2023-02-26 21:51:24 +00:00
|
|
|
} 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:
|
|
|
|
(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(
|
|
|
|
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:
|
|
|
|
book = CashBook(record[0])
|
|
|
|
result['yield_fee_total'][record[0]] = quantize_val(record[1], book)
|
|
|
|
result['yield_dividend_total'][record[0]] = quantize_val(record[2], book)
|
|
|
|
result['yield_sales'][record[0]] = quantize_val(record[3], book)
|
|
|
|
|
|
|
|
for record in records_12m:
|
|
|
|
book = CashBook(record[0])
|
|
|
|
result['yield_fee_12m'][record[0]] = quantize_val(record[1], book)
|
|
|
|
result['yield_dividend_12m'][record[0]] = quantize_val(record[2], book)
|
|
|
|
result['yield_sales_12m'][record[0]] = quantize_val(record[3], book)
|
2023-02-22 15:21:23 +00:00
|
|
|
|
2023-02-26 21:51:24 +00:00
|
|
|
# store to cache
|
|
|
|
MemCache.store_result(cashbooks, cache_keys, result)
|
|
|
|
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()
|
2022-12-23 18:15:20 +00:00
|
|
|
(tab_balance, tab2) = CBook.get_balance_of_cashbook_sql()
|
2023-02-26 21:51:24 +00:00
|
|
|
(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())
|
|
|
|
query = tab_book.join(tab_line,
|
|
|
|
condition=(tab_book.id==tab_line.cashbook),
|
2022-12-24 12:14:51 +00:00
|
|
|
).join(tab_type,
|
|
|
|
condition=tab_book.btype==tab_type.id,
|
2022-12-22 23:34:45 +00:00
|
|
|
).join(tab_cur,
|
|
|
|
condition=tab_book.currency==tab_cur.id,
|
|
|
|
).join(tab_asset,
|
|
|
|
condition=tab_book.asset==tab_asset.id,
|
2023-02-26 21:51:24 +00:00
|
|
|
).join(query_yield,
|
|
|
|
condition=query_yield.id==tab_line.id,
|
2022-12-23 18:15:20 +00:00
|
|
|
).join(tab_balance,
|
|
|
|
condition=tab_book.id==tab_balance.cashbook,
|
|
|
|
type_ = 'LEFT OUTER',
|
2022-12-22 23:34:45 +00:00
|
|
|
).join(tab_rate,
|
|
|
|
condition=tab_book.asset==tab_rate.id,
|
|
|
|
type_ = 'LEFT OUTER',
|
|
|
|
).select(
|
|
|
|
tab_book.id, # 0
|
|
|
|
Coalesce(Sum(Case(
|
2022-12-30 22:55:00 +00:00
|
|
|
(tab_line.date <= query_date,
|
|
|
|
tab_line.quantity_credit - tab_line.quantity_debit),
|
2022-12-22 23:34:45 +00:00
|
|
|
else_ = Decimal('0.0'),
|
|
|
|
)), Decimal('0.0')).as_('quantity'), # 1
|
2022-12-30 22:55:00 +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
|
|
|
|
tab_book.currency, # 4
|
|
|
|
tab_cur.digits.as_('currency_digits'), # 5
|
|
|
|
tab_asset.uom, # 6
|
|
|
|
tab_book.quantity_uom, # 7
|
|
|
|
tab_asset.currency.as_('asset_currency'), #8
|
2022-12-23 18:15:20 +00:00
|
|
|
Coalesce(tab_balance.balance, Decimal('0.0')).as_('balance'), #9
|
2023-02-26 21:51:24 +00:00
|
|
|
(
|
|
|
|
Sum(query_yield.fee) + tab_balance.balance
|
|
|
|
).as_('purchase_amount'), #10
|
2022-12-22 23:34:45 +00:00
|
|
|
group_by=[tab_book.id, tab_rate.rate,
|
|
|
|
tab_book.currency, tab_cur.digits, tab_asset.uom,
|
2022-12-23 18:15:20 +00:00
|
|
|
tab_book.quantity_uom, tab_asset.currency,
|
|
|
|
tab_balance.balance],
|
2023-01-24 20:25:29 +00:00
|
|
|
where=(tab_type.feature == 'asset'),
|
2022-12-22 23:34:45 +00:00
|
|
|
)
|
2023-01-24 20:25:29 +00:00
|
|
|
return (query, tab_book)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_asset_quantity(cls, cashbooks, names):
|
|
|
|
""" get quantities
|
|
|
|
"""
|
|
|
|
pool = Pool()
|
|
|
|
CBook = pool.get('cashbook.book')
|
|
|
|
Uom = pool.get('product.uom')
|
|
|
|
Currency = pool.get('currency.currency')
|
2023-02-26 21:51:24 +00:00
|
|
|
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-01-28 12:03:24 +00:00
|
|
|
result = {x:{y.id: None for y in cashbooks} for x in names}
|
2023-01-24 20:25:29 +00:00
|
|
|
|
2023-02-26 21:51:24 +00:00
|
|
|
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)],
|
|
|
|
}, {
|
|
|
|
'model': 'investment.rate',
|
|
|
|
'query': [('asset.id', '=', x.asset.id)],
|
2023-02-27 09:20:23 +00:00
|
|
|
'cachekey': CACHEKEY_ASSETRATE % x.asset.id,
|
2023-02-26 21:51:24 +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
|
|
|
|
|
2023-01-28 12:03:24 +00:00
|
|
|
def values_from_record(rdata):
|
|
|
|
""" compute values for record
|
|
|
|
"""
|
2022-12-22 23:34:45 +00:00
|
|
|
# uom-factor
|
2023-01-28 12:03:24 +00:00
|
|
|
if rdata[6] == rdata[7]:
|
2022-12-22 23:34:45 +00:00
|
|
|
uom_factor = Decimal('1.0')
|
|
|
|
else :
|
|
|
|
uom_factor = Decimal(
|
2023-01-28 12:03:24 +00:00
|
|
|
Uom.compute_qty(Uom(rdata[6]), 1.0, Uom(rdata[7]), round=False)
|
2022-12-22 23:34:45 +00:00
|
|
|
)
|
|
|
|
|
2022-12-23 18:15:20 +00:00
|
|
|
current_value = Currency.compute(
|
2023-01-28 12:03:24 +00:00
|
|
|
rdata[8],
|
|
|
|
rdata[3] * rdata[1] / uom_factor,
|
|
|
|
rdata[4]
|
2022-12-23 18:15:20 +00:00
|
|
|
)
|
2023-01-28 12:03:24 +00:00
|
|
|
return (record[0], {
|
|
|
|
'quantity': rdata[1],
|
|
|
|
'quantity_all': rdata[2],
|
2022-12-23 18:15:20 +00:00
|
|
|
'current_value': current_value,
|
2022-12-22 23:34:45 +00:00
|
|
|
'current_value_ref': Currency.compute(
|
2023-01-28 12:03:24 +00:00
|
|
|
rdata[8],
|
|
|
|
rdata[3] * rdata[1] / uom_factor,
|
|
|
|
company_currency if company_currency is not None else rdata[8],
|
2022-12-22 23:34:45 +00:00
|
|
|
),
|
2023-02-26 21:51:24 +00:00
|
|
|
'diff_amount': current_value - rdata[10],
|
2022-12-23 18:15:20 +00:00
|
|
|
'diff_percent': (
|
|
|
|
Decimal('100.0') * current_value / \
|
2023-02-26 21:51:24 +00:00
|
|
|
rdata[10] - Decimal('100.0')
|
2023-01-28 12:03:24 +00:00
|
|
|
).quantize(Decimal(str(1/10**rdata[5]))) \
|
2023-02-26 21:51:24 +00:00
|
|
|
if rdata[10] != Decimal('0.0') else None,
|
2022-12-24 12:14:51 +00:00
|
|
|
'current_rate': (
|
2023-01-28 12:03:24 +00:00
|
|
|
current_value / rdata[1]
|
|
|
|
).quantize(Decimal(str(1/10**rdata[5]))) \
|
|
|
|
if rdata[1] != Decimal('0.0') else None,
|
2023-02-26 21:51:24 +00:00
|
|
|
'purchase_amount': record[10].quantize(Decimal(str(1/10**rdata[5]))),
|
|
|
|
'purchase_amount_ref': Currency.compute(
|
|
|
|
rdata[4],
|
|
|
|
record[10],
|
|
|
|
company_currency if company_currency is not None else rdata[4],
|
|
|
|
),
|
2023-01-28 12:03:24 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
result_cache = {}
|
|
|
|
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)
|
|
|
|
result_cache[book_id] = values
|
|
|
|
result_cache[book_id]['balance_ref'] = CBook(book_id).balance_ref
|
|
|
|
|
2023-02-26 21:51:24 +00:00
|
|
|
for name in values.keys():
|
|
|
|
if name not in result.keys():
|
|
|
|
result[name] = {}
|
2023-01-28 12:03:24 +00:00
|
|
|
result[name][book_id] = values[name]
|
|
|
|
|
|
|
|
# add aggregated values of cashbooks without type
|
|
|
|
aggr_names = ['current_value', 'current_value_ref',
|
|
|
|
'diff_amount', 'diff_percent']
|
|
|
|
queried_names = list(set(aggr_names).intersection(set(names)))
|
|
|
|
|
|
|
|
if len(queried_names) > 0:
|
|
|
|
# query all subordered asset-cashbooks for
|
|
|
|
# btype=None-cashbooks
|
|
|
|
query1 = [('btype.feature', '=', 'asset'),
|
|
|
|
('parent', 'child_of', ids_nonebtypes)]
|
|
|
|
if len(result_cache.keys()) > 0:
|
|
|
|
query1.append(('id', 'not in', result_cache.keys()))
|
|
|
|
books_query = CBook.search(query1, query=True)
|
|
|
|
|
|
|
|
# add results to cache
|
|
|
|
(query, tab_book) = cls.get_asset_quantity_sql()
|
|
|
|
query.where &= tab_book.id.in_(books_query)
|
|
|
|
cursor.execute(*query)
|
|
|
|
records = cursor.fetchall()
|
|
|
|
|
|
|
|
for record in records:
|
|
|
|
(book_id, values) = values_from_record(record)
|
|
|
|
result_cache[book_id] = values
|
|
|
|
result_cache[book_id]['balance_ref'] = CBook(book_id).balance_ref
|
|
|
|
|
|
|
|
# aggregate sub-cashbooks to requested cashbooks from cache
|
|
|
|
for id_none in ids_nonebtypes:
|
|
|
|
records = CBook.search([
|
|
|
|
('btype.feature', '=', 'asset'),
|
|
|
|
('parent', 'child_of', [id_none])
|
|
|
|
])
|
|
|
|
|
2023-02-26 21:51:24 +00:00
|
|
|
values = {x:Decimal('0.0') for x in aggr_names+['purchase_amount_ref']}
|
2023-01-28 12:03:24 +00:00
|
|
|
for record in records:
|
2023-02-26 21:51:24 +00:00
|
|
|
for name in aggr_names+['purchase_amount_ref']:
|
2023-01-28 12:03:24 +00:00
|
|
|
values[name] += \
|
|
|
|
result_cache.get(record.id, {}).get(name, Decimal('0.0'))
|
|
|
|
|
|
|
|
# convert current-value-ref in company-currency to
|
|
|
|
# currency of current cashbook
|
|
|
|
cbook = CBook(id_none)
|
|
|
|
values['current_value'] = Currency.compute(
|
|
|
|
company_currency if company_currency is not None else cbook.currency,
|
|
|
|
values['current_value_ref'],
|
|
|
|
cbook.currency,
|
|
|
|
)
|
|
|
|
|
|
|
|
values['diff_amount'] = Currency.compute(
|
|
|
|
company_currency if company_currency is not None else cbook.currency,
|
2023-02-26 21:51:24 +00:00
|
|
|
values['current_value_ref'] - values['purchase_amount_ref'],
|
2023-01-28 12:03:24 +00:00
|
|
|
cbook.currency,
|
|
|
|
)
|
|
|
|
|
|
|
|
values['diff_percent'] = \
|
|
|
|
(Decimal('100.0') * values['current_value_ref'] / \
|
2023-02-26 21:51:24 +00:00
|
|
|
values['purchase_amount_ref'] - Decimal('100.0')
|
2023-01-28 12:03:24 +00:00
|
|
|
).quantize(
|
|
|
|
Decimal(str(1/10**cbook.currency_digits))
|
2023-02-26 21:51:24 +00:00
|
|
|
) if values['purchase_amount_ref'] != Decimal('0.0') else None
|
|
|
|
for name in values.keys():
|
|
|
|
if name not in result.keys():
|
|
|
|
result[name] = {}
|
2023-01-28 12:03:24 +00:00
|
|
|
result[name][id_none] = values[name]
|
2022-12-22 23:34:45 +00:00
|
|
|
|
2023-02-26 21:51:24 +00:00
|
|
|
# store to cache
|
|
|
|
MemCache.store_result(cashbooks, cache_keys, result)
|
|
|
|
return {x:result[x] for x in names}
|
2022-12-22 23:34:45 +00:00
|
|
|
|
2023-01-28 12:03:24 +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([
|
|
|
|
('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
|
|
|
|
|
2022-12-22 15:01:10 +00:00
|
|
|
@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', '-'),
|
|
|
|
'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
|