formatting

This commit is contained in:
Frederik Jaeckel 2023-06-08 14:00:59 +02:00
parent 6c1fac8672
commit ad067475f8
13 changed files with 1126 additions and 709 deletions

View file

@ -45,4 +45,3 @@ class AssetRate(metaclass=PoolMeta):
super(AssetRate, cls).delete(records) super(AssetRate, cls).delete(records)
# end # end

View file

@ -12,13 +12,16 @@ class AssetSetting(ModelSingleton, ModelSQL, ModelView):
'Asset setting' 'Asset setting'
__name__ = 'cashbook.assetconf' __name__ = 'cashbook.assetconf'
fee_category = fields.Many2One(string='Fee category', fee_category = fields.Many2One(
string='Fee category',
model_name='cashbook.category', ondelete='RESTRICT', model_name='cashbook.category', ondelete='RESTRICT',
help='Category for fees when trading assets.') help='Category for fees when trading assets.')
dividend_category = fields.Many2One(string='Dividend category', dividend_category = fields.Many2One(
string='Dividend category',
model_name='cashbook.category', ondelete='RESTRICT', model_name='cashbook.category', ondelete='RESTRICT',
help='Category for dividend paid out.') help='Category for dividend paid out.')
gainloss_book = fields.Many2One(string='Profit/Loss Cashbook', gainloss_book = fields.Many2One(
string='Profit/Loss Cashbook',
model_name='cashbook.book', ondelete='RESTRICT', model_name='cashbook.book', ondelete='RESTRICT',
help='Profit and loss on sale of assets are recorded in the cash book.') help='Profit and loss on sale of assets are recorded in the cash book.')

312
book.py
View file

@ -22,22 +22,27 @@ from .asset import CACHEKEY_ASSETRATE
# enable/disable caching of cachekey for 'currency.rate' # enable/disable caching of cachekey for 'currency.rate'
if config.get('cashbook', 'cache_currency', default='yes').lower() in ['yes', '1', 'true']: if config.get(
'cashbook', 'cache_currency',
default='yes').lower() in ['yes', '1', 'true']:
ENA_CURRKEY = True ENA_CURRKEY = True
else : else:
ENA_CURRKEY = False ENA_CURRKEY = False
# enable/disable caching of cachekey for 'currency.rate' # enable/disable caching of cachekey for 'currency.rate'
if config.get('cashbook', 'cache_asset', default='yes').lower() in ['yes', '1', 'true']: if config.get(
'cashbook', 'cache_asset',
default='yes').lower() in ['yes', '1', 'true']:
ENA_ASSETKEY = True ENA_ASSETKEY = True
else : else:
ENA_ASSETKEY = False ENA_ASSETKEY = False
class Book(SymbolMixin, metaclass=PoolMeta): class Book(SymbolMixin, metaclass=PoolMeta):
__name__ = 'cashbook.book' __name__ = 'cashbook.book'
asset = fields.Many2One(string='Asset', select=True, asset = fields.Many2One(
string='Asset', select=True,
model_name='investment.asset', ondelete='RESTRICT', model_name='investment.asset', ondelete='RESTRICT',
states={ states={
'required': Eval('feature', '') == 'asset', 'required': Eval('feature', '') == 'asset',
@ -47,8 +52,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
Len(Eval('lines')) > 0, Len(Eval('lines')) > 0,
), ),
}, depends=DEPENDS2+['feature', 'lines']) }, depends=DEPENDS2+['feature', 'lines'])
quantity_digits = fields.Integer(string='Digits', quantity_digits = fields.Integer(
help='Quantity Digits', string='Digits', help='Quantity Digits',
domain=[ domain=[
('quantity_digits', '>=', 0), ('quantity_digits', '>=', 0),
('quantity_digits', '<=', 6), ('quantity_digits', '<=', 6),
@ -61,10 +66,12 @@ class Book(SymbolMixin, metaclass=PoolMeta):
Len(Eval('lines')) > 0, Len(Eval('lines')) > 0,
), ),
}, depends=DEPENDS2+['feature', 'lines']) }, depends=DEPENDS2+['feature', 'lines'])
asset_uomcat = fields.Function(fields.Many2One(string='UOM Category', asset_uomcat = fields.Function(fields.Many2One(
readonly=True, model_name='product.uom.category', string='UOM Category', readonly=True,
model_name='product.uom.category',
states={'invisible': True}), 'on_change_with_asset_uomcat') states={'invisible': True}), 'on_change_with_asset_uomcat')
quantity_uom = fields.Many2One(string='UOM', select=True, quantity_uom = fields.Many2One(
string='UOM', select=True,
model_name='product.uom', ondelete='RESTRICT', model_name='product.uom', ondelete='RESTRICT',
domain=[ domain=[
('category.id', '=', Eval('asset_uomcat', -1)), ('category.id', '=', Eval('asset_uomcat', -1)),
@ -77,34 +84,38 @@ class Book(SymbolMixin, metaclass=PoolMeta):
Len(Eval('lines')) > 0, Len(Eval('lines')) > 0,
), ),
}, depends=DEPENDS2+['feature', 'lines', 'asset_uomcat']) }, depends=DEPENDS2+['feature', 'lines', 'asset_uomcat'])
symbol = fields.Function(fields.Char(string='Symbol', readonly=True), symbol = fields.Function(fields.Char(
'on_change_with_symbol') string='Symbol', readonly=True), 'on_change_with_symbol')
asset_symbol = fields.Function(fields.Many2One(string='Symbol', asset_symbol = fields.Function(fields.Many2One(
readonly=True, model_name='cashbook.book'), string='Symbol', readonly=True, model_name='cashbook.book'),
'on_change_with_asset_symbol') 'on_change_with_asset_symbol')
quantity = fields.Function(fields.Numeric(string='Quantity', quantity = fields.Function(fields.Numeric(
help='Quantity of assets until to date', readonly=True, string='Quantity', help='Quantity of assets until to date',
digits=(16, Eval('quantity_digits', 4)), readonly=True, digits=(16, Eval('quantity_digits', 4)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['quantity_digits', 'feature']), }, depends=['quantity_digits', 'feature']),
'get_asset_quantity') 'get_asset_quantity')
quantity_all = fields.Function(fields.Numeric(string='Total Quantity', quantity_all = fields.Function(fields.Numeric(
help='Total quantity of all assets', readonly=True, string='Total Quantity', help='Total quantity of all assets',
digits=(16, Eval('quantity_digits', 4)), readonly=True, digits=(16, Eval('quantity_digits', 4)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['quantity_digits', 'feature']), }, depends=['quantity_digits', 'feature']),
'get_asset_quantity') 'get_asset_quantity')
current_value = fields.Function(fields.Numeric(string='Value', current_value = fields.Function(fields.Numeric(
help='Valuation of the investment based on the current stock market price.', string='Value',
help='Valuation of the investment based on the current ' +
'stock market price.',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('show_performance', False) == False, 'invisible': Eval('show_performance', False) == False,
}, depends=['currency_digits', 'show_performance']), }, depends=['currency_digits', 'show_performance']),
'get_asset_quantity') 'get_asset_quantity')
current_value_ref = fields.Function(fields.Numeric(string='Value (Ref.)', current_value_ref = fields.Function(fields.Numeric(
help='Valuation of the investment based on the current stock exchange price, converted into the company currency.', string='Value (Ref.)',
help='Valuation of the investment based on the current stock' +
' exchange price, converted into the company currency.',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Or( 'invisible': Or(
@ -115,27 +126,35 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'get_asset_quantity') 'get_asset_quantity')
# performance # performance
diff_amount = fields.Function(fields.Numeric(string='Difference', diff_amount = fields.Function(fields.Numeric(
string='Difference',
help='Difference between acquisition value and current value', help='Difference between acquisition value and current value',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('show_performance', False) == False, 'invisible': Eval('show_performance', False) == False,
}, depends=['currency_digits', 'show_performance']), 'get_asset_quantity') }, depends=['currency_digits', 'show_performance']),
diff_percent = fields.Function(fields.Numeric(string='Percent', 'get_asset_quantity')
diff_percent = fields.Function(fields.Numeric(
string='Percent',
help='percentage performance since acquisition', help='percentage performance since acquisition',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('show_performance', False) == False, 'invisible': Eval('show_performance', False) == False,
}, depends=['currency_digits', 'show_performance']), 'get_asset_quantity') }, depends=['currency_digits', 'show_performance']),
show_performance = fields.Function(fields.Boolean(string='Performance', 'get_asset_quantity')
readonly=True), 'on_change_with_show_performance') show_performance = fields.Function(fields.Boolean(
current_rate = fields.Function(fields.Numeric(string='Rate', string='Performance', readonly=True),
help='Rate per unit of investment based on current stock exchange price.', 'on_change_with_show_performance')
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)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']), 'get_asset_quantity') }, depends=['currency_digits', 'feature']), 'get_asset_quantity')
purchase_amount = fields.Function(fields.Numeric(string='Purchase Amount', purchase_amount = fields.Function(fields.Numeric(
string='Purchase Amount',
help='Total purchase amount, from shares and fees.', help='Total purchase amount, from shares and fees.',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
@ -144,43 +163,47 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'get_asset_quantity') 'get_asset_quantity')
# yield # yield
yield_dividend_total = fields.Function(fields.Numeric(string='Dividend', yield_dividend_total = fields.Function(fields.Numeric(
help='Total dividends received', string='Dividend', help='Total dividends received',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']), 'get_yield_data') }, depends=['currency_digits', 'feature']), 'get_yield_data')
yield_dividend_12m = fields.Function(fields.Numeric(string='Dividend 1y', yield_dividend_12m = fields.Function(fields.Numeric(
string='Dividend 1y',
help='Dividends received in the last twelve months', help='Dividends received in the last twelve months',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']), 'get_yield_data') }, depends=['currency_digits', 'feature']), 'get_yield_data')
yield_fee_total = fields.Function(fields.Numeric(string='Trade Fee', yield_fee_total = fields.Function(fields.Numeric(
help='Total trade fees payed', string='Trade Fee', help='Total trade fees payed',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']), 'get_yield_data') }, depends=['currency_digits', 'feature']), 'get_yield_data')
yield_fee_12m = fields.Function(fields.Numeric(string='Trade Fee 1y', yield_fee_12m = fields.Function(fields.Numeric(
string='Trade Fee 1y',
help='Trade fees payed in the last twelve month', help='Trade fees payed in the last twelve month',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']), 'get_yield_data') }, depends=['currency_digits', 'feature']), 'get_yield_data')
yield_sales = fields.Function(fields.Numeric(string='Sales', yield_sales = fields.Function(fields.Numeric(
help='Total profit or loss on sale of shares.', string='Sales', help='Total profit or loss on sale of shares.',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']), 'get_yield_data') }, depends=['currency_digits', 'feature']), 'get_yield_data')
yield_sales_12m = fields.Function(fields.Numeric(string='Sales 1y', yield_sales_12m = fields.Function(fields.Numeric(
string='Sales 1y',
help='Total profit or loss on sale of shares in the last twelve month.', help='Total profit or loss on sale of shares in the last twelve month.',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']), 'get_yield_data') }, depends=['currency_digits', 'feature']), 'get_yield_data')
yield_balance = fields.Function(fields.Numeric(string='Total Yield', yield_balance = fields.Function(fields.Numeric(
string='Total Yield',
help='Total income: price gain + dividends + sales gains - fees', help='Total income: price gain + dividends + sales gains - fees',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
@ -194,9 +217,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
('/tree', 'visual', ('/tree', 'visual',
If(Eval('show_performance', False) == True, If(Eval('show_performance', False) == True,
If(Eval('diff_percent', 0) < 0, 'danger', If(Eval('diff_percent', 0) < 0, 'danger',
If(Eval('diff_percent', 0) > 0, 'success', '') If(Eval('diff_percent', 0) > 0,
), '') 'success', '')), '')),
),
] ]
def get_rec_name(self, name): def get_rec_name(self, name):
@ -205,7 +227,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
recname = super(Book, self).get_rec_name(name) recname = super(Book, self).get_rec_name(name)
if self.feature == 'asset': if self.feature == 'asset':
recname += ' | %(quantity)s %(uom_symbol)s' % { recname += ' | %(quantity)s %(uom_symbol)s' % {
'quantity': Report.format_number(self.quantity or 0.0, None, 'quantity': Report.format_number(
self.quantity or 0.0, None,
digits=self.quantity_digits), digits=self.quantity_digits),
'uom_symbol': getattr(self.quantity_uom, 'symbol', '-'), 'uom_symbol': getattr(self.quantity_uom, 'symbol', '-'),
} }
@ -229,7 +252,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
""" calculate yield total """ calculate yield total
fee is already contained in 'diff_amount' fee is already contained in 'diff_amount'
""" """
sum_lst = [self.diff_amount, self.yield_dividend_total, self.yield_sales] 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]) sum2 = sum([x for x in sum_lst if x is not None])
return sum2 return sum2
@ -252,14 +276,18 @@ class Book(SymbolMixin, metaclass=PoolMeta):
if date_to: if date_to:
where &= tab_line.date <= date_to where &= tab_line.date <= date_to
query = tab_book.join(tab_line, query = tab_book.join(
condition=tab_line.cashbook==tab_book.id, tab_line,
).join(tab_cur, condition=tab_line.cashbook == tab_book.id,
condition=tab_cur.id==tab_book.currency, ).join(
).join(tab_line_yield, tab_cur,
condition=tab_line_yield.id==tab_line.id, condition=tab_cur.id == tab_book.currency,
).join(tab_line_gainloss, ).join(
condition=tab_line_gainloss.id==tab_line.id, tab_line_yield,
condition=tab_line_yield.id == tab_line.id,
).join(
tab_line_gainloss,
condition=tab_line_gainloss.id == tab_line.id,
).select( ).select(
tab_book.id, tab_book.id,
Sum(tab_line_yield.fee).as_('fee'), Sum(tab_line_yield.fee).as_('fee'),
@ -276,14 +304,14 @@ class Book(SymbolMixin, metaclass=PoolMeta):
""" collect yield data """ collect yield data
""" """
pool = Pool() pool = Pool()
CashBook = pool.get('cashbook.book')
IrDate = pool.get('ir.date') IrDate = pool.get('ir.date')
MemCache = pool.get('cashbook.memcache') MemCache = pool.get('cashbook.memcache')
cursor = Transaction().connection.cursor() cursor = Transaction().connection.cursor()
context = Transaction().context context = Transaction().context
result = { result = {
x:{y.id: Decimal('0.0') for y in cashbooks} x: {y.id: Decimal('0.0') for y in cashbooks}
for x in ['yield_fee_total', 'yield_dividend_total', for x in [
'yield_fee_total', 'yield_dividend_total',
'yield_sales', 'yield_fee_12m', 'yield_dividend_12m', 'yield_sales', 'yield_fee_12m', 'yield_dividend_12m',
'yield_sales_12m']} 'yield_sales_12m']}
@ -297,21 +325,23 @@ class Book(SymbolMixin, metaclass=PoolMeta):
query_date = context.get('date', IrDate.today()) query_date = context.get('date', IrDate.today())
cache_keys = { cache_keys = {
x.id: MemCache.get_key_by_record( x.id: MemCache.get_key_by_record(
name = 'get_yield_data', name='get_yield_data',
record = x, record=x,
query = [{ query=[{
'model': 'cashbook.line', 'model': 'cashbook.line',
'query': [('cashbook.parent', 'child_of', [x.id])], 'query': [('cashbook.parent', 'child_of', [x.id])],
}, { }, {
'model': 'currency.currency.rate', 'model': 'currency.currency.rate',
'query': [('currency.id', '=', x.currency.id)], 'query': [('currency.id', '=', x.currency.id)],
'cachekey' if ENA_CURRKEY else 'disabled': CACHEKEY_CURRENCY % x.currency.id, 'cachekey' if ENA_CURRKEY else 'disabled':
CACHEKEY_CURRENCY % x.currency.id,
}, { }, {
'model': 'investment.rate', 'model': 'investment.rate',
'query': [('asset.id', '=', x.asset.id)], 'query': [('asset.id', '=', x.asset.id)],
'cachekey' if ENA_ASSETKEY else 'disabled': CACHEKEY_ASSETRATE % x.asset.id, 'cachekey' if ENA_ASSETKEY else 'disabled':
CACHEKEY_ASSETRATE % x.asset.id,
} if x.asset is not None else {}], } if x.asset is not None else {}],
addkeys = [query_date.isoformat()]) addkeys=[query_date.isoformat()])
for x in cashbooks for x in cashbooks
} }
@ -332,26 +362,32 @@ class Book(SymbolMixin, metaclass=PoolMeta):
# results for 12 months # results for 12 months
(tab_book2, query_12m) = cls.get_yield_data_sql( (tab_book2, query_12m) = cls.get_yield_data_sql(
date_to = query_date, date_to=query_date,
date_from = query_date - timedelta(days=365), 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 todo_cashbook])
cursor.execute(*query_12m) cursor.execute(*query_12m)
records_12m = cursor.fetchall() records_12m = cursor.fetchall()
for record in records_total: for record in records_total:
result['yield_fee_total'][record[0]] = quantize_val(record[1], record[4]) result['yield_fee_total'][record[0]] = quantize_val(
result['yield_dividend_total'][record[0]] = quantize_val(record[2], record[4]) record[1], record[4])
result['yield_sales'][record[0]] = quantize_val(record[3], 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])
for record in records_12m: for record in records_12m:
result['yield_fee_12m'][record[0]] = quantize_val(record[1], record[4]) result['yield_fee_12m'][record[0]] = quantize_val(
result['yield_dividend_12m'][record[0]] = quantize_val(record[2], record[4]) record[1], record[4])
result['yield_sales_12m'][record[0]] = quantize_val(record[3], 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])
# store to cache # store to cache
MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook) MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook)
return {x:result[x] for x in names} return {x: result[x] for x in names}
@classmethod @classmethod
def get_asset_quantity_sql(cls): def get_asset_quantity_sql(cls):
@ -374,40 +410,50 @@ class Book(SymbolMixin, metaclass=PoolMeta):
context = Transaction().context context = Transaction().context
query_date = context.get('qdate', CurrentDate()) query_date = context.get('qdate', CurrentDate())
query = tab_book.join(tab_line, query = tab_book.join(
condition=(tab_book.id==tab_line.cashbook), tab_line,
).join(tab_type, condition=(tab_book.id == tab_line.cashbook),
condition=tab_book.btype==tab_type.id, ).join(
).join(tab_cur, tab_type,
condition=tab_book.currency==tab_cur.id, condition=tab_book.btype == tab_type.id,
).join(tab_asset, ).join(
condition=tab_book.asset==tab_asset.id, tab_cur,
).join(query_yield, condition=tab_book.currency == tab_cur.id,
condition=query_yield.id==tab_line.id, ).join(
).join(tab_balance, tab_asset,
condition=tab_book.id==tab_balance.cashbook, condition=tab_book.asset == tab_asset.id,
type_ = 'LEFT OUTER', ).join(
).join(tab_rate, query_yield,
condition=tab_book.asset==tab_rate.id, condition=query_yield.id == tab_line.id,
type_ = 'LEFT OUTER', ).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',
).select( ).select(
tab_book.id, # 0 tab_book.id, # 0
Coalesce(Sum(Case( Coalesce(Sum(Case(
(tab_line.date <= query_date, (tab_line.date <= query_date,
tab_line.quantity_credit - tab_line.quantity_debit), tab_line.quantity_credit - tab_line.quantity_debit),
else_ = Decimal('0.0'), else_=Decimal('0.0'),
)), Decimal('0.0')).as_('quantity'), # 1 )), Decimal('0.0')).as_('quantity'), # 1
Sum(tab_line.quantity_credit - tab_line.quantity_debit).as_('quantity_all'), # 2 Sum(
tab_line.quantity_credit -
tab_line.quantity_debit).as_('quantity_all'), # 2
Coalesce(tab_rate.rate, Decimal('0.0')).as_('rate'), # 3 Coalesce(tab_rate.rate, Decimal('0.0')).as_('rate'), # 3
tab_book.currency, # 4 tab_book.currency, # 4
tab_cur.digits.as_('currency_digits'), # 5 tab_cur.digits.as_('currency_digits'), # 5
tab_asset.uom, # 6 tab_asset.uom, # 6
tab_book.quantity_uom, # 7 tab_book.quantity_uom, # 7
tab_asset.currency.as_('asset_currency'), #8 tab_asset.currency.as_('asset_currency'), # 8
( (
Sum(query_yield.fee) + tab_balance.balance Sum(query_yield.fee) + tab_balance.balance
).as_('purchase_amount'), #9 ).as_('purchase_amount'), # 9
group_by=[tab_book.id, tab_rate.rate, group_by=[
tab_book.id, tab_rate.rate,
tab_book.currency, tab_cur.digits, tab_asset.uom, tab_book.currency, tab_cur.digits, tab_asset.uom,
tab_book.quantity_uom, tab_asset.currency, tab_book.quantity_uom, tab_asset.currency,
tab_balance.balance], tab_balance.balance],
@ -434,8 +480,9 @@ class Book(SymbolMixin, metaclass=PoolMeta):
company_currency = CBook.default_currency() company_currency = CBook.default_currency()
result = { result = {
x:{y.id: None for y in cashbooks} x: {y.id: None for y in cashbooks}
for x in ['quantity', 'quantity_all', 'current_value', for x in [
'quantity', 'quantity_all', 'current_value',
'current_value_ref', 'diff_amount', 'diff_percent', 'current_value_ref', 'diff_amount', 'diff_percent',
'current_rate', 'purchase_amount', 'purchase_amount_ref', 'current_rate', 'purchase_amount', 'purchase_amount_ref',
'digits'] 'digits']
@ -443,19 +490,21 @@ class Book(SymbolMixin, metaclass=PoolMeta):
cache_keys = { cache_keys = {
x.id: MemCache.get_key_by_record( x.id: MemCache.get_key_by_record(
name = 'get_asset_quantity', name='get_asset_quantity',
record = x, record=x,
query = [{ query=[{
'model': 'cashbook.line', 'model': 'cashbook.line',
'query': [('cashbook.parent', 'child_of', [x.id])], 'query': [('cashbook.parent', 'child_of', [x.id])],
}, { }, {
'model': 'currency.currency.rate', 'model': 'currency.currency.rate',
'query': [('currency.id', '=', x.currency.id)], 'query': [('currency.id', '=', x.currency.id)],
'cachekey' if ENA_CURRKEY else 'disabled': CACHEKEY_CURRENCY % x.currency.id, 'cachekey' if ENA_CURRKEY else 'disabled':
CACHEKEY_CURRENCY % x.currency.id,
}, { }, {
'model': 'investment.rate', 'model': 'investment.rate',
'query': [('asset.id', '=', x.asset.id)], 'query': [('asset.id', '=', x.asset.id)],
'cachekey' if ENA_ASSETKEY else 'disabled': CACHEKEY_ASSETRATE % x.asset.id, 'cachekey' if ENA_ASSETKEY else 'disabled':
CACHEKEY_ASSETRATE % x.asset.id,
} if x.asset is not None else {}], } if x.asset is not None else {}],
addkeys=[ addkeys=[
str(company_currency), str(company_currency),
@ -476,9 +525,11 @@ class Book(SymbolMixin, metaclass=PoolMeta):
# uom-factor # uom-factor
if rdata[6] == rdata[7]: if rdata[6] == rdata[7]:
uom_factor = Decimal('1.0') uom_factor = Decimal('1.0')
else : else:
uom_factor = Decimal( uom_factor = Decimal(
Uom.compute_qty(Uom(rdata[6]), 1.0, Uom(rdata[7]), round=False) Uom.compute_qty(
Uom(rdata[6]), 1.0,
Uom(rdata[7]), round=False)
) )
current_value = Currency.compute( current_value = Currency.compute(
@ -493,23 +544,26 @@ class Book(SymbolMixin, metaclass=PoolMeta):
'current_value_ref': Currency.compute( 'current_value_ref': Currency.compute(
rdata[8], rdata[8],
rdata[3] * rdata[1] / uom_factor, rdata[3] * rdata[1] / uom_factor,
company_currency if company_currency is not None else rdata[8], company_currency
if company_currency is not None else rdata[8],
), ),
'diff_amount': current_value - rdata[9], 'diff_amount': current_value - rdata[9],
'diff_percent': ( 'diff_percent': (
Decimal('100.0') * current_value / \ Decimal('100.0') * current_value /
rdata[9] - Decimal('100.0') rdata[9] - Decimal('100.0')
).quantize(Decimal(str(1/10**rdata[5]))) \ ).quantize(Decimal(str(1/10**rdata[5])))
if rdata[9] != Decimal('0.0') else None, if rdata[9] != Decimal('0.0') else None,
'current_rate': ( 'current_rate': (
current_value / rdata[1] current_value / rdata[1]
).quantize(Decimal(str(1/10**rdata[5]))) \ ).quantize(Decimal(str(1/10**rdata[5])))
if rdata[1] != Decimal('0.0') else None, if rdata[1] != Decimal('0.0') else None,
'purchase_amount': record[9].quantize(Decimal(str(1/10**rdata[5]))), 'purchase_amount': record[9].quantize(
Decimal(str(1/10**rdata[5]))),
'purchase_amount_ref': Currency.compute( 'purchase_amount_ref': Currency.compute(
rdata[4], rdata[4],
record[9], record[9],
company_currency if company_currency is not None else rdata[4], company_currency
if company_currency is not None else rdata[4],
), ),
}) })
@ -529,7 +583,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
result[name][book_id] = values[name] result[name][book_id] = values[name]
# add aggregated values of cashbooks without type # add aggregated values of cashbooks without type
aggr_names = ['current_value', 'current_value_ref', aggr_names = [
'current_value', 'current_value_ref',
'diff_amount', 'diff_percent'] 'diff_amount', 'diff_percent']
queried_names = list(set(aggr_names).intersection(set(names))) queried_names = list(set(aggr_names).intersection(set(names)))
@ -539,10 +594,12 @@ class Book(SymbolMixin, metaclass=PoolMeta):
(tab_quantity, tab_book) = cls.get_asset_quantity_sql() (tab_quantity, tab_book) = cls.get_asset_quantity_sql()
tab_subids = sub_ids_hierarchical('cashbook.book') tab_subids = sub_ids_hierarchical('cashbook.book')
query = tab_book.join(tab_subids, query = tab_book.join(
condition=tab_book.id==tab_subids.parent, tab_subids,
).join(tab_quantity, condition=tab_book.id == tab_subids.parent,
condition=tab_quantity.id==AnyInArray(tab_subids.subids), ).join(
tab_quantity,
condition=tab_quantity.id == AnyInArray(tab_subids.subids),
).select( ).select(
tab_book.id, tab_book.id,
Sum(tab_quantity.quantity), # 1 Sum(tab_quantity.quantity), # 1
@ -556,10 +613,11 @@ class Book(SymbolMixin, metaclass=PoolMeta):
Sum(tab_quantity.purchase_amount), # 9 Sum(tab_quantity.purchase_amount), # 9
tab_book.currency.as_('currency_book'), # 10 tab_book.currency.as_('currency_book'), # 10
where=tab_book.id.in_(ids_nonebtypes), where=tab_book.id.in_(ids_nonebtypes),
group_by=[tab_book.id, tab_quantity.rate, group_by=[
tab_book.id, tab_quantity.rate,
tab_quantity.currency, tab_quantity.currency_digits, tab_quantity.currency, tab_quantity.currency_digits,
tab_quantity.uom, tab_quantity.quantity_uom, tab_quantity.uom, tab_quantity.quantity_uom,
tab_quantity.asset_currency,tab_book.currency], tab_quantity.asset_currency, tab_book.currency],
) )
cursor.execute(*query) cursor.execute(*query)
records = cursor.fetchall() records = cursor.fetchall()
@ -567,7 +625,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
for record in records: for record in records:
(book_id, values) = values_from_record(record) (book_id, values) = values_from_record(record)
for name in ['current_value', 'diff_amount', for name in [
'current_value', 'diff_amount',
'current_value_ref', 'purchase_amount_ref']: 'current_value_ref', 'purchase_amount_ref']:
if result[name][book_id] is None: if result[name][book_id] is None:
result[name][book_id] = Decimal('0.0') result[name][book_id] = Decimal('0.0')
@ -575,14 +634,17 @@ class Book(SymbolMixin, metaclass=PoolMeta):
value = Decimal('0.0') value = Decimal('0.0')
if name == 'current_value': if name == 'current_value':
value = Currency.compute( value = Currency.compute(
company_currency if company_currency is not None else record[4], company_currency
if company_currency is not None else record[4],
values['current_value_ref'], values['current_value_ref'],
record[10], record[10],
) )
elif name == 'diff_amount': elif name == 'diff_amount':
value = Currency.compute( value = Currency.compute(
company_currency if company_currency is not None else record[4], company_currency
values['current_value_ref'] - values['purchase_amount_ref'], if company_currency is not None else record[4],
values['current_value_ref'] -
values['purchase_amount_ref'],
record[10], record[10],
) )
elif name in ['current_value_ref', 'purchase_amount_ref']: elif name in ['current_value_ref', 'purchase_amount_ref']:
@ -596,7 +658,8 @@ class Book(SymbolMixin, metaclass=PoolMeta):
p_amount = result['purchase_amount_ref'][id_book] p_amount = result['purchase_amount_ref'][id_book]
digits = result['digits'][id_book] digits = result['digits'][id_book]
if (p_amount == Decimal('0.0')) or (p_amount is None) or (c_val is None): if (p_amount == Decimal('0.0')) or \
(p_amount is None) or (c_val is None):
continue continue
result['diff_percent'][id_book] = ( result['diff_percent'][id_book] = (
@ -606,7 +669,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
# store to cache # store to cache
MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook) MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook)
return {x:result[x] for x in names} return {x: result[x] for x in names}
@fields.depends('id') @fields.depends('id')
def on_change_with_show_performance(self, name=None): def on_change_with_show_performance(self, name=None):
@ -617,8 +680,7 @@ class Book(SymbolMixin, metaclass=PoolMeta):
if Book2.search_count([ if Book2.search_count([
('btype.feature', '=', 'asset'), ('btype.feature', '=', 'asset'),
('parent', 'child_of', [self.id]), ('parent', 'child_of', [self.id])]) > 0:
]) > 0:
return True return True
return False return False

163
line.py
View file

@ -85,7 +85,8 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
quantity_balance = fields.Function(fields.Numeric( quantity_balance = fields.Function(fields.Numeric(
string='Quantity', string='Quantity',
digits=(16, Eval('quantity_digits', 4)), readonly=True, digits=(16, Eval('quantity_digits', 4)), readonly=True,
help='Number of shares in the cashbook up to the current row if the default sort applies.', help='Number of shares in the cashbook up to the current ' +
'row if the default sort applies.',
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['quantity_digits', 'feature']), }, depends=['quantity_digits', 'feature']),
@ -97,7 +98,8 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
# performance # performance
current_value = fields.Function(fields.Numeric( current_value = fields.Function(fields.Numeric(
string='Value', string='Value',
help='Valuation of the investment based on the current stock market price.', help='Valuation of the investment based on the current ' +
'stock market price.',
readonly=True, digits=(16, Eval('currency_digits', 2)), readonly=True, digits=(16, Eval('currency_digits', 2)),
states={ states={
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
@ -154,60 +156,69 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
SplitLine = pool.get('cashbook.split') SplitLine = pool.get('cashbook.split')
tab_line = cls.__table__() tab_line = cls.__table__()
tab_mvsp_counterpart = cls.__table__() tab_mvsp_counterpart = cls.__table__()
tab_mvsp_local = cls.__table__()
tab_mvmv_counterpart = cls.__table__() tab_mvmv_counterpart = cls.__table__()
tab_spmv_counterpart = cls.__table__() tab_spmv_counterpart = cls.__table__()
tab_mv_spline = SplitLine.__table__() tab_mv_spline = SplitLine.__table__()
cfg1 = AssetSetting.get_singleton() cfg1 = AssetSetting.get_singleton()
gainloss_book = getattr(getattr(cfg1, 'gainloss_book', None), 'id', None) gainloss_book = getattr(getattr(
cfg1, 'gainloss_book', None), 'id', None)
tab_assetline = cls.search([ tab_assetline = cls.search([
('cashbook.btype.feature', '=', 'asset'), ('cashbook.btype.feature', '=', 'asset'),
], query=True) ], query=True)
query = tab_line.join(tab_assetline, query = tab_line.join(
condition=(tab_assetline.id==tab_line.id), tab_assetline,
condition=(tab_assetline.id == tab_line.id),
).join(tab_mvsp_counterpart, ).join(
# [MV-SP] transfer booking, select counterpart [1] - a split-booking tab_mvsp_counterpart,
# [MV-SP] transfer booking,
# select counterpart [1] - a split-booking
condition=tab_line.bookingtype.in_(['mvin', 'mvout']) & \ condition=tab_line.bookingtype.in_(['mvin', 'mvout']) & \
((tab_line.reference == tab_mvsp_counterpart.id) | \ ((tab_line.reference == tab_mvsp_counterpart.id) |
(tab_line.id == tab_mvsp_counterpart.reference)) & \ (tab_line.id == tab_mvsp_counterpart.reference)) &
(tab_mvsp_counterpart.bookingtype.in_(['spin', 'spout'])), (tab_mvsp_counterpart.bookingtype.in_(['spin', 'spout'])),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_mv_spline, ).join(
# [MV-SP] line is linked to split-booking-line of counterpart [1] tab_mv_spline,
# [MV-SP] line is linked to split-booking-line
# of counterpart [1]
condition=(tab_mv_spline.line == tab_mvsp_counterpart.id) & \ condition=(tab_mv_spline.line == tab_mvsp_counterpart.id) & \
(tab_mv_spline.splittype == 'tr') & \ (tab_mv_spline.splittype == 'tr') & \
(tab_mv_spline.booktransf != None) & \ (tab_mv_spline.booktransf != None) & \
(tab_mv_spline.booktransf == gainloss_book), (tab_mv_spline.booktransf == gainloss_book),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_spmv_counterpart, ).join(
# [SP-MV] split booking, select counterpart [1] - a transfer-booking tab_spmv_counterpart,
# [SP-MV] split booking, select counterpart [1]
# - a transfer-booking
condition=tab_line.bookingtype.in_(['spin', 'spout']) & \ condition=tab_line.bookingtype.in_(['spin', 'spout']) & \
((tab_line.reference == tab_spmv_counterpart.id) | \ ((tab_line.reference == tab_spmv_counterpart.id) | \
(tab_line.id == tab_spmv_counterpart.reference)) & \ (tab_line.id == tab_spmv_counterpart.reference)) & \
tab_spmv_counterpart.bookingtype.in_(['mvin', 'mvout']) & \ tab_spmv_counterpart.bookingtype.in_(['mvin', 'mvout']) & \
(tab_spmv_counterpart.cashbook == gainloss_book), (tab_spmv_counterpart.cashbook == gainloss_book),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_mvmv_counterpart, ).join(
tab_mvmv_counterpart,
# [MV-MV] transfer booking # [MV-MV] transfer booking
condition=tab_line.bookingtype.in_(['mvin', 'mvout']) & \ condition=tab_line.bookingtype.in_(['mvin', 'mvout']) & \
((tab_mvmv_counterpart.reference == tab_line.id) | \ ((tab_mvmv_counterpart.reference == tab_line.id) | \
(tab_mvmv_counterpart.id == tab_line.reference)) & \ (tab_mvmv_counterpart.id == tab_line.reference)) & \
tab_mvmv_counterpart.bookingtype.in_(['mvin', 'mvout']) & \ tab_mvmv_counterpart.bookingtype.in_(['mvin', 'mvout']) & \
(tab_mvmv_counterpart.cashbook == gainloss_book), (tab_mvmv_counterpart.cashbook == gainloss_book),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).select( ).select(
tab_line.id, tab_line.id,
(Coalesce( (Coalesce(
tab_mvmv_counterpart.credit - tab_mvmv_counterpart.debit, tab_mvmv_counterpart.credit - tab_mvmv_counterpart.debit,
Case( Case(
(tab_line.bookingtype == 'mvin', tab_mv_spline.amount), (tab_line.bookingtype == 'mvin', tab_mv_spline.amount),
(tab_line.bookingtype == 'mvout', tab_mv_spline.amount * Decimal('-1.0')), (tab_line.bookingtype == 'mvout',
tab_mv_spline.amount * Decimal('-1.0')),
), ),
Case( Case(
(tab_mvsp_counterpart.cashbook == gainloss_book, (tab_mvsp_counterpart.cashbook == gainloss_book,
@ -238,67 +249,79 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
cfg1 = AssetSetting.get_singleton() cfg1 = AssetSetting.get_singleton()
fee_category = getattr(getattr(cfg1, 'fee_category', None), 'id', None) fee_category = getattr(getattr(cfg1, 'fee_category', None), 'id', None)
dividend_category = getattr(getattr(cfg1, 'dividend_category', None), 'id', None) dividend_category = getattr(getattr(
cfg1, 'dividend_category', None), 'id', None)
tab_assetline = cls.search([ tab_assetline = cls.search([
('cashbook.btype.feature', '=', 'asset'), ('cashbook.btype.feature', '=', 'asset'),
], query=True) ], query=True)
query = tab_line.join(tab_assetline, query = tab_line.join(
condition=(tab_assetline.id==tab_line.id), tab_assetline,
).join(tab_inout_fee, condition=(tab_assetline.id == tab_line.id),
).join(
tab_inout_fee,
# [INOUT] fee, local booked # [INOUT] fee, local booked
condition=(tab_inout_fee.id==tab_line.id) & \ condition=(tab_inout_fee.id == tab_line.id) & \
tab_inout_fee.bookingtype.in_(['in', 'out']) & \ tab_inout_fee.bookingtype.in_(['in', 'out']) & \
(tab_inout_fee.category != None) & \ (tab_inout_fee.category != None) & \
(tab_inout_fee.category == fee_category), (tab_inout_fee.category == fee_category),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_inout_divi, ).join(
tab_inout_divi,
# [INOUT] dividend, local booked # [INOUT] dividend, local booked
condition=(tab_inout_divi.id==tab_line.id) & \ condition=(tab_inout_divi.id == tab_line.id) & \
tab_inout_divi.bookingtype.in_(['in', 'out']) & \ tab_inout_divi.bookingtype.in_(['in', 'out']) & \
(tab_inout_divi.category != None) & \ (tab_inout_divi.category != None) & \
(tab_inout_divi.category == dividend_category), (tab_inout_divi.category == dividend_category),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_mv_counterpart, ).join(
# [MV] transfer booking, select counterpart [1] - a split-booking tab_mv_counterpart,
# [MV] transfer booking, select counterpart [1]
# - a split-booking
condition=tab_line.bookingtype.in_(['mvin', 'mvout']) & \ condition=tab_line.bookingtype.in_(['mvin', 'mvout']) & \
((tab_line.reference == tab_mv_counterpart.id) | \ ((tab_line.reference == tab_mv_counterpart.id) | \
(tab_line.id == tab_mv_counterpart.reference)) & \ (tab_line.id == tab_mv_counterpart.reference)) & \
(tab_mv_counterpart.bookingtype.in_(['spin', 'spout'])), (tab_mv_counterpart.bookingtype.in_(['spin', 'spout'])),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_mv_spline_fee, ).join(
# [MV] fee-line is linked to split-booking-line of counterpart [1] tab_mv_spline_fee,
# [MV] fee-line is linked to split-booking-line
# of counterpart [1]
condition=(tab_mv_spline_fee.line == tab_mv_counterpart.id) & \ condition=(tab_mv_spline_fee.line == tab_mv_counterpart.id) & \
(tab_mv_spline_fee.splittype == 'cat') & \ (tab_mv_spline_fee.splittype == 'cat') & \
(tab_mv_spline_fee.category != None) & \ (tab_mv_spline_fee.category != None) & \
(tab_mv_spline_fee.category == fee_category), (tab_mv_spline_fee.category == fee_category),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_mv_spline_divi, ).join(
# [MV] dividend-line is linked to split-booking-line of counterpart [1] tab_mv_spline_divi,
# [MV] dividend-line is linked to split-booking-line
# of counterpart [1]
condition=(tab_mv_spline_divi.line == tab_mv_counterpart.id) & \ condition=(tab_mv_spline_divi.line == tab_mv_counterpart.id) & \
(tab_mv_spline_divi.splittype == 'cat') & \ (tab_mv_spline_divi.splittype == 'cat') & \
(tab_mv_spline_divi.category != None) & \ (tab_mv_spline_divi.category != None) & \
(tab_mv_spline_divi.category == dividend_category), (tab_mv_spline_divi.category == dividend_category),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_spline_fee, ).join(
tab_spline_fee,
# [SP] fee, split booking # [SP] fee, split booking
condition=(tab_spline_fee.line == tab_line.id) & \ condition=(tab_spline_fee.line == tab_line.id) & \
tab_line.bookingtype.in_(['spin', 'spout']) & \ tab_line.bookingtype.in_(['spin', 'spout']) & \
(tab_spline_fee.splittype == 'cat') & \ (tab_spline_fee.splittype == 'cat') & \
(tab_spline_fee.category != None) & \ (tab_spline_fee.category != None) & \
(tab_spline_fee.category == fee_category), (tab_spline_fee.category == fee_category),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).join(tab_spline_divi, ).join(
tab_spline_divi,
# [SP] dividend, split booking # [SP] dividend, split booking
condition=(tab_spline_divi.line == tab_line.id) & \ condition=(tab_spline_divi.line == tab_line.id) & \
tab_line.bookingtype.in_(['spin', 'spout']) & \ tab_line.bookingtype.in_(['spin', 'spout']) & \
(tab_spline_divi.splittype == 'cat') & \ (tab_spline_divi.splittype == 'cat') & \
(tab_spline_divi.category != None) & \ (tab_spline_divi.category != None) & \
(tab_spline_divi.category == dividend_category), (tab_spline_divi.category == dividend_category),
type_ = 'LEFT OUTER', type_='LEFT OUTER',
).select( ).select(
tab_line.id, tab_line.id,
Sum(Coalesce( Sum(Coalesce(
@ -308,8 +331,10 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
# transfer = fee is positive # transfer = fee is positive
tab_mv_spline_fee.amount, tab_mv_spline_fee.amount,
Case( Case(
(tab_line.bookingtype == 'spin', tab_spline_fee.amount * Decimal('-1.0')), (tab_line.bookingtype == 'spin',
(tab_line.bookingtype == 'spout', tab_spline_fee.amount), tab_spline_fee.amount * Decimal('-1.0')),
(tab_line.bookingtype == 'spout',
tab_spline_fee.amount),
), ),
Decimal('0.0'), Decimal('0.0'),
)).as_('fee'), )).as_('fee'),
@ -317,8 +342,10 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
tab_inout_divi.credit - tab_inout_divi.debit, tab_inout_divi.credit - tab_inout_divi.debit,
tab_mv_spline_divi.amount, tab_mv_spline_divi.amount,
Case( Case(
(tab_line.bookingtype == 'spin', tab_spline_divi.amount), (tab_line.bookingtype == 'spin',
(tab_line.bookingtype == 'spout', tab_spline_divi.amount * Decimal('-1.0')), tab_spline_divi.amount),
(tab_line.bookingtype == 'spout',
tab_spline_divi.amount * Decimal('-1.0')),
), ),
Decimal('0.0'), Decimal('0.0'),
)).as_('dividend'), )).as_('dividend'),
@ -380,7 +407,7 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
value or Decimal('0.0') value or Decimal('0.0')
).quantize(Decimal(str(1/10**line.currency_digits))) ).quantize(Decimal(str(1/10**line.currency_digits)))
result = {x:{y.id: None for y in lines} for x in names} result = {x: {y.id: None for y in lines} for x in names}
# read fee, dividend # read fee, dividend
name_set = set({'trade_fee', 'asset_dividend'}).intersection(set(names)) name_set = set({'trade_fee', 'asset_dividend'}).intersection(set(names))
@ -408,7 +435,8 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
for record in records: for record in records:
line = Line2(record[0]) line = Line2(record[0])
result['asset_gainloss'][record[0]] = quantize_val(record[1], line) result['asset_gainloss'][record[0]] = quantize_val(
record[1], line)
return result return result
def get_rec_name(self, name): def get_rec_name(self, name):
@ -416,10 +444,13 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
""" """
recname = super(Line, self).get_rec_name(name) recname = super(Line, self).get_rec_name(name)
if self.cashbook.feature == 'asset': if self.cashbook.feature == 'asset':
credit = self.quantity_credit if self.quantity_credit is not None else Decimal('0.0') credit = self.quantity_credit \
debit = self.quantity_debit if self.quantity_debit is not None else Decimal('0.0') if self.quantity_credit is not None else Decimal('0.0')
debit = self.quantity_debit \
if self.quantity_debit is not None else Decimal('0.0')
recname += '|%(quantity)s %(uom_symbol)s' % { recname += '|%(quantity)s %(uom_symbol)s' % {
'quantity': Report.format_number(credit - debit, 'quantity': Report.format_number(
credit - debit,
lang=None, digits=self.quantity_digits), lang=None, digits=self.quantity_digits),
'uom_symbol': getattr(self.quantity_uom, 'symbol', '-'), 'uom_symbol': getattr(self.quantity_uom, 'symbol', '-'),
} }
@ -453,10 +484,12 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
cashbook = Cashbook.browse([id_cashbook])[0] cashbook = Cashbook.browse([id_cashbook])[0]
if isinstance(values, dict): if isinstance(values, dict):
type_ = values.get('bookingtype', getattr(line, 'bookingtype', None)) type_ = values.get(
'bookingtype', getattr(line, 'bookingtype', None))
quantity = values.get('quantity', None) quantity = values.get('quantity', None)
else : else:
type_ = getattr(values, 'bookingtype', getattr(line, 'bookingtype', None)) type_ = getattr(
values, 'bookingtype', getattr(line, 'bookingtype', None))
quantity = getattr(values, 'quantity', None) quantity = getattr(values, 'quantity', None)
if (type_ is not None) and (cashbook.feature == 'asset'): if (type_ is not None) and (cashbook.feature == 'asset'):
@ -471,7 +504,7 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
'quantity_debit': quantity, 'quantity_debit': quantity,
'quantity_credit': Decimal('0.0'), 'quantity_credit': Decimal('0.0'),
}) })
else : else:
raise ValueError('invalid "bookingtype"') raise ValueError('invalid "bookingtype"')
return result return result
@ -482,22 +515,26 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
""" """
result = super(Line, cls).get_counterpart_values( result = super(Line, cls).get_counterpart_values(
line, line,
splitline = splitline, splitline=splitline,
values = values values=values
) )
line_uom = getattr(line.quantity_uom, 'id', None) line_uom = getattr(line.quantity_uom, 'id', None)
booktransf_uom = getattr(getattr(line.booktransf, 'quantity_uom', {}), 'id', None) booktransf_uom = getattr(getattr(
line.booktransf, 'quantity_uom', {}), 'id', None)
if getattr(splitline, 'quantity', None) is not None: if getattr(splitline, 'quantity', None) is not None:
# we add values to the counterpart of a splitbooking-line # we add values to the counterpart of a splitbooking-line
asset_books = sum([ asset_books = sum([
1 if splitline.feature == 'asset' else 0, 1 if splitline.feature == 'asset' else 0,
1 if getattr(splitline.booktransf, 'feature', '-') == 'asset' else 0, 1 if getattr(
splitline.booktransf, 'feature', '-') == 'asset' else 0,
]) ])
diff_uom = False diff_uom = False
if asset_books == 2: if asset_books == 2:
diff_uom = (splitline.quantity_uom != splitline.booktransf.quantity_uom) and \ diff_uom = (
splitline.quantity_uom !=
splitline.booktransf.quantity_uom) and \
(splitline.quantity_uom is not None) and \ (splitline.quantity_uom is not None) and \
(splitline.booktransf.quantity_uom is not None) (splitline.booktransf.quantity_uom is not None)
@ -565,7 +602,8 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
if (self.quantity is not None) and \ if (self.quantity is not None) and \
(self.amount is not None) and \ (self.amount is not None) and \
(self.cashbook.current_rate is not None): (self.cashbook.current_rate is not None):
return (self.quantity * self.cashbook.current_rate - return (
self.quantity * self.cashbook.current_rate -
self.amount).quantize( self.amount).quantize(
Decimal(str(1/10**self.currency_digits))) Decimal(str(1/10**self.currency_digits)))
@ -579,7 +617,8 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
(self.amount is not None) and \ (self.amount is not None) and \
(self.amount != Decimal('0.0')) and \ (self.amount != Decimal('0.0')) and \
(self.cashbook.current_rate is not None): (self.cashbook.current_rate is not None):
return (self.quantity * self.cashbook.current_rate * return (
self.quantity * self.cashbook.current_rate *
Decimal('100.0') / self.amount - Decimal('100.0') Decimal('100.0') / self.amount - Decimal('100.0')
).quantize(Decimal(str(1/10**self.currency_digits))) ).quantize(Decimal(str(1/10**self.currency_digits)))

View file

@ -6,7 +6,6 @@
from trytond.model import fields from trytond.model import fields
from trytond.pyson import Eval, Bool, Or from trytond.pyson import Eval, Bool, Or
from trytond.pool import Pool from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.exceptions import UserError from trytond.exceptions import UserError
from trytond.i18n import gettext from trytond.i18n import gettext
from trytond.modules.product.uom import uom_conversion_digits from trytond.modules.product.uom import uom_conversion_digits
@ -22,7 +21,8 @@ DEPENDSQ.extend(DEPENDS)
class SecondUomMixin(object): class SecondUomMixin(object):
""" two fields for second uom: quantity, rate """ two fields for second uom: quantity, rate
""" """
quantity_2nd_uom = fields.Numeric(string='Quantity Second UOM', quantity_2nd_uom = fields.Numeric(
string='Quantity Second UOM',
digits=(16, Eval('quantity2nd_digits', 4)), digits=(16, Eval('quantity2nd_digits', 4)),
states={ states={
'readonly': Or( 'readonly': Or(
@ -32,8 +32,10 @@ class SecondUomMixin(object):
'required': Bool(Eval('quantity2nd')), 'required': Bool(Eval('quantity2nd')),
'invisible': ~Bool(Eval('quantity2nd')), 'invisible': ~Bool(Eval('quantity2nd')),
}, depends=DEPENDSQ+['quantity2nd_digits', 'quantity2nd']) }, depends=DEPENDSQ+['quantity2nd_digits', 'quantity2nd'])
factor_2nd_uom = fields.Function(fields.Numeric(string='Conversion factor', factor_2nd_uom = fields.Function(fields.Numeric(
help='Conversion factor between the units of the participating cash books.', string='Conversion factor',
help='Conversion factor between the units of the ' +
'participating cash books.',
digits=uom_conversion_digits, digits=uom_conversion_digits,
states={ states={
'readonly': Or( 'readonly': Or(
@ -45,15 +47,18 @@ class SecondUomMixin(object):
}, depends=DEPENDSQ+['quantity2nd_digits', 'quantity2nd']), }, depends=DEPENDSQ+['quantity2nd_digits', 'quantity2nd']),
'on_change_with_factor_2nd_uom', setter='set_factor_2nd_uom') 'on_change_with_factor_2nd_uom', setter='set_factor_2nd_uom')
quantity2nd = fields.Function(fields.Many2One(model_name='product.uom', quantity2nd = fields.Function(fields.Many2One(
model_name='product.uom',
string="2nd UOM", readonly=True), 'on_change_with_quantity2nd') string="2nd UOM", readonly=True), 'on_change_with_quantity2nd')
quantity2nd_digits = fields.Function(fields.Integer(string='2nd UOM Digits', quantity2nd_digits = fields.Function(fields.Integer(
readonly=True), 'on_change_with_quantity2nd_digits') string='2nd UOM Digits', readonly=True),
'on_change_with_quantity2nd_digits')
def quantize_quantity(self, value): def quantize_quantity(self, value):
""" quantize for line-quantity """ quantize for line-quantity
""" """
return Decimal(value).quantize(Decimal(Decimal(1) / 10 ** self.quantity_digits)) return Decimal(value).quantize(
Decimal(Decimal(1) / 10 ** self.quantity_digits))
@classmethod @classmethod
def add_2nd_quantity(cls, values, from_uom): def add_2nd_quantity(cls, values, from_uom):
@ -74,11 +79,12 @@ class SecondUomMixin(object):
if booktransf.quantity_uom: if booktransf.quantity_uom:
if from_uom.id != booktransf.quantity_uom.id: if from_uom.id != booktransf.quantity_uom.id:
# deny impossible transfer # deny impossible transfer
if from_uom.category.id != booktransf.quantity_uom.category.id: if from_uom.category.id != \
booktransf.quantity_uom.category.id:
raise UserError(gettext( raise UserError(gettext(
'cashbook_investment.msg_uomcat_mismatch', 'cashbook_investment.msg_uomcat_mismatch',
cat1 = from_uom.category.rec_name, cat1=from_uom.category.rec_name,
cat2 = booktransf.quantity_uom.category.rec_name, cat2=booktransf.quantity_uom.category.rec_name,
)) ))
values['quantity_2nd_uom'] = Decimal(UOM.compute_qty( values['quantity_2nd_uom'] = Decimal(UOM.compute_qty(
@ -87,7 +93,8 @@ class SecondUomMixin(object):
booktransf.quantity_uom, booktransf.quantity_uom,
round=False, round=False,
)).quantize(Decimal( )).quantize(Decimal(
Decimal(1) / 10 ** booktransf.quantity_digits) Decimal(1) /
10 ** booktransf.quantity_digits)
) )
return values return values
@ -124,24 +131,27 @@ class SecondUomMixin(object):
if len(to_write) > 0: if len(to_write) > 0:
Line2.write(*to_write) Line2.write(*to_write)
@fields.depends('booktransf', '_parent_booktransf.quantity_uom', \ @fields.depends(
'quantity_uom', 'quantity_digits', 'quantity', \ 'booktransf', '_parent_booktransf.quantity_uom',
'quantity_uom', 'quantity_digits', 'quantity',
'quantity_2nd_uom', 'factor_2nd_uom') 'quantity_2nd_uom', 'factor_2nd_uom')
def on_change_booktransf(self): def on_change_booktransf(self):
""" update quantity_2nd_uom """ update quantity_2nd_uom
""" """
self.on_change_factor_2nd_uom() self.on_change_factor_2nd_uom()
@fields.depends('booktransf', '_parent_booktransf.quantity_uom', \ @fields.depends(
'quantity_uom', 'quantity_digits', 'quantity', \ 'booktransf', '_parent_booktransf.quantity_uom',
'quantity_uom', 'quantity_digits', 'quantity',
'quantity_2nd_uom', 'factor_2nd_uom') 'quantity_2nd_uom', 'factor_2nd_uom')
def on_change_quantity(self): def on_change_quantity(self):
""" update quantity_2nd_uom """ update quantity_2nd_uom
""" """
self.on_change_factor_2nd_uom() self.on_change_factor_2nd_uom()
@fields.depends('booktransf', '_parent_booktransf.quantity_uom', \ @fields.depends(
'quantity_uom', 'quantity_digits', 'quantity', \ 'booktransf', '_parent_booktransf.quantity_uom',
'quantity_uom', 'quantity_digits', 'quantity',
'quantity_2nd_uom', 'factor_2nd_uom') 'quantity_2nd_uom', 'factor_2nd_uom')
def on_change_factor_2nd_uom(self): def on_change_factor_2nd_uom(self):
""" update quantity_2nd_uom + factor_2nd_uom """ update quantity_2nd_uom + factor_2nd_uom
@ -168,8 +178,9 @@ class SecondUomMixin(object):
if self.quantity != Decimal('0.0'): if self.quantity != Decimal('0.0'):
self.factor_2nd_uom = ( self.factor_2nd_uom = (
self.quantity_2nd_uom / self.quantity self.quantity_2nd_uom / self.quantity
).quantize(Decimal(Decimal(1) / 10 ** uom_conversion_digits[1])) ).quantize(Decimal(
else : Decimal(1) / 10 ** uom_conversion_digits[1]))
else:
self.quantity_2nd_uom = self.quantize_quantity( self.quantity_2nd_uom = self.quantize_quantity(
self.quantity * self.factor_2nd_uom) self.quantity * self.factor_2nd_uom)
@ -188,7 +199,8 @@ class SecondUomMixin(object):
exp = Decimal(Decimal(1) / 10 ** uom_conversion_digits[1]) exp = Decimal(Decimal(1) / 10 ** uom_conversion_digits[1])
return (self.quantity_2nd_uom / self.quantity).quantize(exp) return (self.quantity_2nd_uom / self.quantity).quantize(exp)
@fields.depends('booktransf', '_parent_booktransf.quantity_uom', 'quantity_uom') @fields.depends(
'booktransf', '_parent_booktransf.quantity_uom', 'quantity_uom')
def on_change_with_quantity2nd(self, name=None): def on_change_with_quantity2nd(self, name=None):
""" uom of transfer-target """ uom of transfer-target
""" """

View file

@ -14,22 +14,24 @@ from decimal import Decimal
class Reconciliation(metaclass=PoolMeta): class Reconciliation(metaclass=PoolMeta):
__name__ = 'cashbook.recon' __name__ = 'cashbook.recon'
start_quantity = fields.Numeric(string='Start Quantity', start_quantity = fields.Numeric(
readonly=True, digits=(16, Eval('quantity_digits', 4)), string='Start Quantity', readonly=True,
digits=(16, Eval('quantity_digits', 4)),
states={ states={
'required': Eval('feature', '') == 'asset', 'required': Eval('feature', '') == 'asset',
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['quantity_digits', 'feature']) }, depends=['quantity_digits', 'feature'])
end_quantity = fields.Numeric(string='End Quantity', end_quantity = fields.Numeric(
readonly=True, digits=(16, Eval('quantity_digits', 4)), string='End Quantity', readonly=True,
digits=(16, Eval('quantity_digits', 4)),
states={ states={
'required': Eval('feature', '') == 'asset', 'required': Eval('feature', '') == 'asset',
'invisible': Eval('feature', '') != 'asset', 'invisible': Eval('feature', '') != 'asset',
}, depends=['quantity_digits', 'feature']) }, depends=['quantity_digits', 'feature'])
quantity_digits = fields.Function(fields.Integer(string='Quantity Digits'), quantity_digits = fields.Function(fields.Integer(
'on_change_with_quantity_digits') string='Quantity Digits'), 'on_change_with_quantity_digits')
quantity_uom = fields.Function(fields.Many2One(string='Symbol', quantity_uom = fields.Function(fields.Many2One(
readonly=True, model_name='product.uom'), string='Symbol', readonly=True, model_name='product.uom'),
'on_change_with_quantity_uom') 'on_change_with_quantity_uom')
def get_rec_name(self, name): def get_rec_name(self, name):
@ -38,9 +40,11 @@ class Reconciliation(metaclass=PoolMeta):
recname = super(Reconciliation, self).get_rec_name(name) recname = super(Reconciliation, self).get_rec_name(name)
if self.cashbook.feature == 'asset': if self.cashbook.feature == 'asset':
recname += ' | %(start_quantity)s %(uom_symbol)s - %(end_quantity)s %(uom_symbol)s' % { recname += ' | %(start_quantity)s %(uom_symbol)s - %(end_quantity)s %(uom_symbol)s' % {
'start_quantity': Report.format_number(self.start_quantity or 0.0, None, 'start_quantity': Report.format_number(
self.start_quantity or 0.0, None,
digits=self.quantity_digits), digits=self.quantity_digits),
'end_quantity': Report.format_number(self.end_quantity or 0.0, None, 'end_quantity': Report.format_number(
self.end_quantity or 0.0, None,
digits=self.quantity_digits), digits=self.quantity_digits),
'uom_symbol': getattr(self.quantity_uom, 'symbol', '-'), 'uom_symbol': getattr(self.quantity_uom, 'symbol', '-'),
} }
@ -94,7 +98,7 @@ class Reconciliation(metaclass=PoolMeta):
if reconciliation.predecessor: if reconciliation.predecessor:
values['start_quantity'] = reconciliation.predecessor.end_quantity values['start_quantity'] = reconciliation.predecessor.end_quantity
else : else:
values['start_quantity'] = Decimal('0.0') values['start_quantity'] = Decimal('0.0')
values['end_quantity'] = values['start_quantity'] values['end_quantity'] = values['start_quantity']

View file

@ -2,7 +2,7 @@
""" """
# Always prefer setuptools over distutils # Always prefer setuptools over distutils
from setuptools import setup, find_packages from setuptools import setup
# To use a consistent encoding # To use a consistent encoding
from codecs import open from codecs import open
from os import path from os import path
@ -36,7 +36,7 @@ with open(path.join(here, 'versiondep.txt'), encoding='utf-8') as f:
l2 = i.strip().split(';') l2 = i.strip().split(';')
if len(l2) < 4: if len(l2) < 4:
continue continue
modversion[l2[0]] = {'min':l2[1], 'max':l2[2], 'prefix':l2[3]} modversion[l2[0]] = {'min': l2[1], 'max': l2[2], 'prefix': l2[3]}
# tryton-version # tryton-version
major_version = 6 major_version = 6
@ -51,19 +51,22 @@ for dep in info.get('depends', []):
prefix = modversion[dep]['prefix'] prefix = modversion[dep]['prefix']
if len(modversion[dep]['max']) > 0: if len(modversion[dep]['max']) > 0:
requires.append('%s_%s >= %s, <= %s' % requires.append('%s_%s >= %s, <= %s' % (
(prefix, dep, modversion[dep]['min'], modversion[dep]['max'])) prefix, dep, modversion[dep]['min'],
else : modversion[dep]['max']))
requires.append('%s_%s >= %s' % else:
(prefix, dep, modversion[dep]['min'])) requires.append('%s_%s >= %s' % (
else : prefix, dep, modversion[dep]['min']))
requires.append('%s_%s >= %s.%s, < %s.%s' % else:
('trytond', dep, major_version, minor_version, requires.append(
'%s_%s >= %s.%s, < %s.%s' % (
'trytond', dep, major_version, minor_version,
major_version, minor_version + 1)) major_version, minor_version + 1))
requires.append('trytond >= %s.%s, < %s.%s' % requires.append('trytond >= %s.%s, < %s.%s' % (
(major_version, minor_version, major_version, minor_version + 1)) major_version, minor_version, major_version, minor_version + 1))
setup(name='%s_%s' % (PREFIX, MODULE), setup(
name='%s_%s' % (PREFIX, MODULE),
version=info.get('version', '0.0.1'), version=info.get('version', '0.0.1'),
description='Tryton module to add investment accounts to cashbook.', description='Tryton module to add investment accounts to cashbook.',
long_description=long_description, long_description=long_description,
@ -97,7 +100,8 @@ setup(name='%s_%s' % (PREFIX, MODULE),
'trytond.modules.%s' % MODULE, 'trytond.modules.%s' % MODULE,
], ],
package_data={ package_data={
'trytond.modules.%s' % MODULE: (info.get('xml', []) 'trytond.modules.%s' % MODULE: (
info.get('xml', [])
+ ['tryton.cfg', 'locale/*.po', 'tests/*.py', + ['tryton.cfg', 'locale/*.po', 'tests/*.py',
'view/*.xml', 'docs/*.txt', 'view/*.xml', 'docs/*.txt',
'versiondep.txt', 'README.rst']), 'versiondep.txt', 'README.rst']),

View file

@ -22,17 +22,18 @@ STATESQ1A['readonly'] = ~And(
Eval('booktransf_feature', '') == 'asset', Eval('booktransf_feature', '') == 'asset',
)) ))
class SplitLine(SecondUomMixin, metaclass=PoolMeta): class SplitLine(SecondUomMixin, metaclass=PoolMeta):
__name__ = 'cashbook.split' __name__ = 'cashbook.split'
quantity = fields.Numeric(string='Quantity', quantity = fields.Numeric(
digits=(16, Eval('quantity_digits', 4)), string='Quantity', digits=(16, Eval('quantity_digits', 4)),
states=STATESQ1A, depends=DEPENDSQ1) states=STATESQ1A, depends=DEPENDSQ1)
quantity_digits = fields.Function(fields.Integer(string='Digits', quantity_digits = fields.Function(fields.Integer(
readonly=True, states={'invisible': True}), string='Digits', readonly=True, states={'invisible': True}),
'on_change_with_quantity_digits') 'on_change_with_quantity_digits')
quantity_uom = fields.Function(fields.Many2One(string='Symbol', quantity_uom = fields.Function(fields.Many2One(
readonly=True, model_name='product.uom'), string='Symbol', readonly=True, model_name='product.uom'),
'on_change_with_quantity_uom') 'on_change_with_quantity_uom')
def get_rec_name(self, name): def get_rec_name(self, name):
@ -41,13 +42,15 @@ class SplitLine(SecondUomMixin, metaclass=PoolMeta):
recname = super(SplitLine, self).get_rec_name(name) recname = super(SplitLine, self).get_rec_name(name)
if self.line.cashbook.feature == 'asset': if self.line.cashbook.feature == 'asset':
recname += '|%(quantity)s %(uom_symbol)s' % { recname += '|%(quantity)s %(uom_symbol)s' % {
'quantity': Report.format_number(self.quantity or 0.0, None, 'quantity': Report.format_number(
self.quantity or 0.0, None,
digits=self.quantity_digits), digits=self.quantity_digits),
'uom_symbol': self.quantity_uom.symbol, 'uom_symbol': self.quantity_uom.symbol,
} }
return recname return recname
@fields.depends('line', '_parent_line.cashbook', 'booktransf', \ @fields.depends(
'line', '_parent_line.cashbook', 'booktransf',
'_parent_booktransf.feature', '_parent_booktransf.quantity_uom') '_parent_booktransf.feature', '_parent_booktransf.quantity_uom')
def on_change_with_quantity_uom(self, name=None): def on_change_with_quantity_uom(self, name=None):
""" get quantity-unit of asset """ get quantity-unit of asset
@ -61,7 +64,8 @@ class SplitLine(SecondUomMixin, metaclass=PoolMeta):
if self.booktransf.quantity_uom: if self.booktransf.quantity_uom:
return self.booktransf.quantity_uom.id return self.booktransf.quantity_uom.id
@fields.depends('line', '_parent_line.cashbook', 'booktransf', \ @fields.depends(
'line', '_parent_line.cashbook', 'booktransf',
'_parent_booktransf.feature', '_parent_booktransf.quantity_digits') '_parent_booktransf.feature', '_parent_booktransf.quantity_digits')
def on_change_with_quantity_digits(self, name=None): def on_change_with_quantity_digits(self, name=None):
""" get digits from cashbook """ get digits from cashbook
@ -85,7 +89,8 @@ class SplitLine(SecondUomMixin, metaclass=PoolMeta):
line = Line2(values.get('line', None)) line = Line2(values.get('line', None))
if line: if line:
values.update(cls.add_2nd_quantity(values, line.cashbook.quantity_uom)) values.update(cls.add_2nd_quantity(
values, line.cashbook.quantity_uom))
return values return values
# end SplitLine # end SplitLine

View file

@ -4,25 +4,14 @@
import trytond.tests.test_tryton import trytond.tests.test_tryton
import unittest import unittest
from trytond.modules.cashbook_investment.tests.test_book import CbInvTestCase from .test_module import CashbookInvestmentTestCase
from trytond.modules.cashbook_investment.tests.test_reconciliation import ReconTestCase
from trytond.modules.cashbook_investment.tests.test_yield import YieldTestCase
__all__ = ['suite'] __all__ = ['suite']
class CashbookInvestmentTestCase(\
CbInvTestCase,\
ReconTestCase,\
YieldTestCase,\
):
'Test cashbook-investment module'
module = 'cashbook_investment'
# end CashbookInvestmentTestCase
def suite(): def suite():
suite = trytond.tests.test_tryton.suite() suite = trytond.tests.test_tryton.suite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(CashbookInvestmentTestCase)) suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
CashbookInvestmentTestCase))
return suite return suite

File diff suppressed because it is too large Load diff

View file

@ -3,18 +3,15 @@
# The COPYRIGHT file at the top level of this repository contains the # The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms. # full copyright notices and license terms.
from trytond.tests.test_tryton import ModuleTestCase, with_transaction from trytond.tests.test_tryton import with_transaction
from trytond.pool import Pool from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.exceptions import UserError
from datetime import date from datetime import date
from decimal import Decimal from decimal import Decimal
class ReconTestCase(ModuleTestCase): class ReconTestCase(object):
'Test quantity reconciliation module' """ test reconciliation
module = 'cashbook_investment' """
@with_transaction() @with_transaction()
def test_recon_set_start_quantity_by_cashbook(self): def test_recon_set_start_quantity_by_cashbook(self):
""" set start-quantity of reconciliation from cashbook-setting """ set start-quantity of reconciliation from cashbook-setting
@ -33,7 +30,7 @@ class ReconTestCase(ModuleTestCase):
}]) }])
asset = self.prep_asset_item( asset = self.prep_asset_item(
company=company, company=company,
product = self.prep_asset_product(name='Product 1')) product=self.prep_asset_product(name='Product 1'))
self.assertEqual(asset.symbol, 'usd/u') self.assertEqual(asset.symbol, 'usd/u')
book, = Book.create([{ book, = Book.create([{
@ -53,12 +50,16 @@ class ReconTestCase(ModuleTestCase):
}]) }])
self.assertEqual(book.name, 'Asset-Book') self.assertEqual(book.name, 'Asset-Book')
self.assertEqual(book.reconciliations[0].feature, 'asset') self.assertEqual(book.reconciliations[0].feature, 'asset')
self.assertEqual(book.reconciliations[0].rec_name, self.assertEqual(
'05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0] | 0.0000 u - 0.0000 u') book.reconciliations[0].rec_name,
'05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0] ' +
'| 0.0000 u - 0.0000 u')
Reconciliation.wfcheck(list(book.reconciliations)) Reconciliation.wfcheck(list(book.reconciliations))
self.assertEqual(book.reconciliations[0].rec_name, self.assertEqual(
'05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0] | 0.0000 u - 0.0000 u') book.reconciliations[0].rec_name,
'05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0] ' +
'| 0.0000 u - 0.0000 u')
@with_transaction() @with_transaction()
def test_recon_set_start_quantity_by_predecessor(self): def test_recon_set_start_quantity_by_predecessor(self):
@ -79,7 +80,7 @@ class ReconTestCase(ModuleTestCase):
}]) }])
asset = self.prep_asset_item( asset = self.prep_asset_item(
company=company, company=company,
product = self.prep_asset_product(name='Product 1')) product=self.prep_asset_product(name='Product 1'))
self.assertEqual(asset.symbol, 'usd/u') self.assertEqual(asset.symbol, 'usd/u')
category = self.prep_category(cattype='in') category = self.prep_category(cattype='in')
@ -119,8 +120,10 @@ class ReconTestCase(ModuleTestCase):
}]) }])
self.assertEqual(book.name, 'Asset-Book') self.assertEqual(book.name, 'Asset-Book')
self.assertEqual(len(book.reconciliations), 1) self.assertEqual(len(book.reconciliations), 1)
self.assertEqual(book.reconciliations[0].rec_name, self.assertEqual(
'05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0] | 0.000 u - 0.000 u') book.reconciliations[0].rec_name,
'05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0] | ' +
'0.000 u - 0.000 u')
self.assertEqual(len(book.reconciliations[0].lines), 0) self.assertEqual(len(book.reconciliations[0].lines), 0)
Lines.wfcheck(list(book.lines)) Lines.wfcheck(list(book.lines))
@ -134,8 +137,10 @@ class ReconTestCase(ModuleTestCase):
self.assertEqual(book.lines[1].quantity_balance, Decimal('4.0')) self.assertEqual(book.lines[1].quantity_balance, Decimal('4.0'))
self.assertEqual(book.reconciliations[0].state, 'check') self.assertEqual(book.reconciliations[0].state, 'check')
self.assertEqual(book.reconciliations[0].rec_name, self.assertEqual(
'05/01/2022 - 05/31/2022 | 0.00 usd - 12.00 usd [2] | 0.000 u - 4.000 u') book.reconciliations[0].rec_name,
'05/01/2022 - 05/31/2022 | 0.00 usd - 12.00 usd [2] ' +
'| 0.000 u - 4.000 u')
Reconciliation.wfdone(list(book.reconciliations)) Reconciliation.wfdone(list(book.reconciliations))
self.assertEqual(book.reconciliations[0].state, 'done') self.assertEqual(book.reconciliations[0].state, 'done')
@ -144,10 +149,14 @@ class ReconTestCase(ModuleTestCase):
'date_from': date(2022, 5, 31), 'date_from': date(2022, 5, 31),
'date_to': date(2022, 6, 30), 'date_to': date(2022, 6, 30),
}]) }])
self.assertEqual(recons[0].rec_name, self.assertEqual(
'05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0] | 0.000 u - 0.000 u') recons[0].rec_name,
'05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0] | ' +
'0.000 u - 0.000 u')
Reconciliation.wfcheck(recons) Reconciliation.wfcheck(recons)
self.assertEqual(recons[0].rec_name, self.assertEqual(
'05/31/2022 - 06/30/2022 | 12.00 usd - 12.00 usd [0] | 4.000 u - 4.000 u') recons[0].rec_name,
'05/31/2022 - 06/30/2022 | 12.00 usd - 12.00 usd [0] | ' +
'4.000 u - 4.000 u')
# end ReconTestCase # end ReconTestCase

28
tests/test_module.py Normal file
View file

@ -0,0 +1,28 @@
# -*- 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.modules.cashbook.tests import CashbookTestCase
from trytond.modules.investment.tests import InvestmentTestCase
from .yieldtest import YieldTestCase
from .book import CbInvTestCase
from .reconciliation import ReconTestCase
class CashbookInvestmentTestCase(
CashbookTestCase,
InvestmentTestCase,
CbInvTestCase,
ReconTestCase,
YieldTestCase):
'Test cashbook-investment module'
module = 'cashbook_investment'
# end CashbookInvestmentTestCase
del CashbookTestCase
del InvestmentTestCase

View file

@ -7,13 +7,12 @@ from decimal import Decimal
from datetime import date from datetime import date
from trytond.pool import Pool from trytond.pool import Pool
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.tests.test_tryton import ModuleTestCase, with_transaction from trytond.tests.test_tryton import with_transaction
class YieldTestCase(ModuleTestCase): class YieldTestCase(object):
'Test yield calculation module' """ test yield
module = 'cashbook_investment' """
def prep_yield_config(self, fee, dividend, gainloss, company): def prep_yield_config(self, fee, dividend, gainloss, company):
""" add config for yield-calculation """ add config for yield-calculation
fee: name of fee-category, fee: name of fee-category,