line: add fields 'Fee' + 'Dividend' - todos

This commit is contained in:
Frederik Jaeckel 2023-02-12 00:09:56 +01:00
parent 43c9a1a2fa
commit c70d2fef7a
12 changed files with 569 additions and 0 deletions

View file

@ -9,6 +9,7 @@ from .book import Book
from .reconciliation import Reconciliation from .reconciliation import Reconciliation
from .line import Line from .line import Line
from .splitline import SplitLine from .splitline import SplitLine
from .assetsetting import AssetSetting
def register(): def register():
@ -18,4 +19,5 @@ def register():
Line, Line,
SplitLine, SplitLine,
Reconciliation, Reconciliation,
AssetSetting,
module='cashbook_investment', type_='model') module='cashbook_investment', type_='model')

24
assetsetting.py Normal file
View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# This file is part of the cashbook-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
from trytond.model import ModelSingleton, ModelView, ModelSQL, fields
class AssetSetting(ModelSingleton, ModelSQL, ModelView):
'Asset setting'
__name__ = 'cashbook.assetconf'
fee_category = fields.Many2One(string='Fee category',
model_name='cashbook.category', ondelete='RESTRICT',
help='Category for fees when trading assets.')
dividend_category = fields.Many2One(string='Dividend category',
model_name='cashbook.category', ondelete='RESTRICT',
help='Category for dividend paid out.')
gainloss_book = fields.Many2One(string='Profit/Loss Cashbook',
model_name='cashbook.book', ondelete='RESTRICT',
help='Profit and loss on sale of assets are recorded in the cash book.')
# end AssetSetting

53
assetsetting.xml Normal file
View file

@ -0,0 +1,53 @@
<?xml version="1.0"?>
<!-- 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. -->
<tryton>
<data>
<record model="ir.ui.view" id="assetconf_view_form">
<field name="model">cashbook.assetconf</field>
<field name="type">form</field>
<field name="name">assetconf_form</field>
</record>
<record model="ir.action.act_window" id="act_assetconf_form">
<field name="name">Asset setting</field>
<field name="res_model">cashbook.assetconf</field>
</record>
<record model="ir.action.act_window.view" id="act_assetconf_form-1">
<field name="sequence" eval="10"/>
<field name="view" ref="assetconf_view_form"/>
<field name="act_window" ref="act_assetconf_form"/>
</record>
<!-- permission -->
<!-- anon: deny all -->
<record model="ir.model.access" id="asset_conf-anon">
<field name="model" search="[('model', '=', 'cashbook.assetconf')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<!-- group_cashbook_admin: read/write -->
<record model="ir.model.access" id="asset_conf-group_cashbook_admin">
<field name="model" search="[('model', '=', 'cashbook.assetconf')]"/>
<field name="group" ref="cashbook.group_cashbook_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- cashbook: read only -->
<record model="ir.model.access" id="asset_conf-group_cashbook">
<field name="model" search="[('model', '=', 'cashbook.assetconf')]"/>
<field name="group" ref="cashbook.group_cashbook"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
</data>
</tryton>

137
line.py
View file

@ -4,12 +4,14 @@
# full copyright notices and license terms. # full copyright notices and license terms.
from decimal import Decimal from decimal import Decimal
from sql.conditionals import Coalesce
from trytond.model import fields from trytond.model import fields
from trytond.pool import PoolMeta, Pool from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Or, If, And from trytond.pyson import Eval, Or, If, And
from trytond.exceptions import UserError from trytond.exceptions import UserError
from trytond.i18n import gettext from trytond.i18n import gettext
from trytond.report import Report from trytond.report import Report
from trytond.transaction import Transaction
from trytond.modules.cashbook.line import STATES, DEPENDS from trytond.modules.cashbook.line import STATES, DEPENDS
from .mixin import SecondUomMixin from .mixin import SecondUomMixin
@ -108,6 +110,141 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
}, depends=['currency_digits', 'feature']), }, depends=['currency_digits', 'feature']),
'on_change_with_diff_percent') 'on_change_with_diff_percent')
trade_fee = fields.Function(fields.Numeric(string='Fee',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states = {
'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']),
'get_yield_data')
asset_dividend = fields.Function(fields.Numeric(string='Dividend',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states = {
'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']),
'get_yield_data')
asset_gainloss = fields.Function(fields.Numeric(string='Profit/Loss',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states = {
'invisible': Eval('feature', '') != 'asset',
}, depends=['currency_digits', 'feature']),
'get_yield_data')
@classmethod
def get_yield_data_sql(cls):
""" query for fee, dividend, gain/loss
"""
pool = Pool()
AssetSetting = pool.get('cashbook.assetconf')
SplitLine = pool.get('cashbook.split')
tab_line = cls.__table__()
tab_line1 = cls.__table__()
tab_line2 = cls.__table__()
tab_line_fee = cls.__table__()
tab_line_divi = cls.__table__()
tab_spline_fee = SplitLine.__table__()
tab_spline_divi = SplitLine.__table__()
cfg1 = AssetSetting.get_singleton()
# local booked fee/dividend
tab_inout = cls.search([
('cashbook.btype.feature', '=', 'asset'),
('bookingtype', 'in', ['in', 'out']),
('category', '!=', None),
], query=True)
query_inout = tab_inout.join(tab_line_fee,
condition=(tab_line_fee.id==tab_inout.id) & \
(tab_line_fee.category == getattr(cfg1.fee_category, 'id', None)),
type_ = 'LEFT OUTER',
).join(tab_line_divi,
condition=(tab_line_divi.id==tab_inout.id) & \
(tab_line_divi.category == getattr(cfg1.dividend_category, 'id', None)),
type_ = 'LEFT OUTER',
).select(
tab_inout.id,
(tab_line_fee.credit - tab_line_fee.debit).as_('fee'),
(tab_line_divi.credit - tab_line_divi.debit).as_('dividend'),
)
# fee/dividend - in counterpart booking
tab_mvinout = cls.search([
('cashbook.btype.feature', '=', 'asset'),
('bookingtype', 'in', ['mvin', 'mvout']),
], query=True)
query_mvinout = tab_mvinout.join(tab_line1,
condition=tab_mvinout.id==tab_line1.id,
).join(tab_line2,
# current line is linked to split-booking-line of counterpart
condition=((tab_line1.reference == tab_line2.id) | \
(tab_line1.id == tab_line2.reference)) & \
(tab_line2.bookingtype.in_(['spin', 'spout'])),
).join(tab_spline_fee,
# fee-line is linked to split-booking-line
condition=(tab_spline_fee.line == tab_line2.id) & \
(tab_spline_fee.splittype == 'cat') & \
(tab_spline_fee.category != None) & \
(tab_spline_fee.category == getattr(cfg1.fee_category, 'id', None)),
type_ = 'LEFT OUTER',
).join(tab_spline_divi,
# dividend-line is linked to split-booking-line
condition=(tab_spline_divi.line == tab_line2.id) & \
(tab_spline_divi.splittype == 'cat') & \
(tab_spline_divi.category != None) & \
(tab_spline_divi.category == getattr(cfg1.dividend_category, 'id', None)),
type_ = 'LEFT OUTER',
).select(
tab_line1.id,
tab_spline_fee.amount.as_('fee'),
tab_spline_divi.amount.as_('dividend'),
)
# together
query = tab_line.join(query_inout,
condition=query_inout.id==tab_line.id,
type_ = 'LEFT OUTER',
).join(query_mvinout,
condition=query_mvinout.id==tab_line.id,
type_ = 'LEFT OUTER',
).select(
tab_line.id,
Coalesce(query_inout.fee, query_mvinout.fee).as_('fee'),
Coalesce(query_inout.dividend, query_mvinout.dividend).as_('dividend'),
)
return (tab_line, query)
@classmethod
def get_yield_data(cls, lines, names):
""" collect data for fee, dividend, gain/loss per line
"""
Line2 = Pool().get('cashbook.line')
(tab_line, query) = cls.get_yield_data_sql()
cursor = Transaction().connection.cursor()
def quantize_val(value, line):
""" quantize...
"""
return (
value or Decimal('0.0')
).quantize(Decimal(str(1/10**line.currency_digits)))
result = {x:{y.id: None for y in lines} for x in names}
query.where = tab_line.id.in_([x.id for x in lines])
cursor.execute(*query)
records = cursor.fetchall()
for record in records:
line = Line2(record[0])
values = {
'trade_fee': quantize_val(record[1], line),
'asset_dividend': quantize_val(record[2], line),
'asset_gainloss': Decimal('0.0'), #quantize_val(record[3], line),
}
for name in names:
result[name][record[0]] = values[name]
return result
def get_rec_name(self, name): def get_rec_name(self, name):
""" add quantities - if its a asset-cashbook """ add quantities - if its a asset-cashbook
""" """

View file

@ -23,6 +23,22 @@ msgid "Cannot transfer quantities between cashbooks with different unit-categori
msgstr "Es können keine Mengen zwischen Kassenbüchern mit verschiedenen Einheitenkategorien (%(cat1)s != %(cat2)s) übertragen werden." msgstr "Es können keine Mengen zwischen Kassenbüchern mit verschiedenen Einheitenkategorien (%(cat1)s != %(cat2)s) übertragen werden."
##############
# ir.ui.menu #
##############
msgctxt "model:ir.ui.menu,name:menu_assetconf"
msgid "Asset setting"
msgstr "Vermögenswert"
#############
# ir.action #
#############
msgctxt "model:ir.action,name:act_assetconf_form"
msgid "Asset setting"
msgstr "Vermögenswert-Einstellung"
################# #################
# cashbook.book # # cashbook.book #
################# #################
@ -246,6 +262,18 @@ msgctxt "help:cashbook.line,diff_percent:"
msgid "percentage performance since acquisition" msgid "percentage performance since acquisition"
msgstr "prozentuale Wertentwicklung seit Anschaffung" msgstr "prozentuale Wertentwicklung seit Anschaffung"
msgctxt "field:cashbook.line,trade_fee:"
msgid "Fee"
msgstr "Gebühr"
msgctxt "field:cashbook.line,asset_dividend:"
msgid "Dividend"
msgstr "Dividende"
msgctxt "field:cashbook.line,asset_gainloss:"
msgid "Profit/Loss"
msgstr "Gewinn/Verlust"
################## ##################
# cashbook.recon # # cashbook.recon #
@ -265,3 +293,35 @@ msgstr "Anzahl-Dezimalstellen"
msgctxt "field:cashbook.recon,quantity_uom:" msgctxt "field:cashbook.recon,quantity_uom:"
msgid "Symbol" msgid "Symbol"
msgstr "Symbol" msgstr "Symbol"
######################
# cashbook.assetconf #
######################
msgctxt "model:cashbook.assetconf,name:"
msgid "Asset setting"
msgstr "Vermögenswert-Einstellung"
msgctxt "field:cashbook.assetconf,fee_category:"
msgid "Fee category"
msgstr "Gebührenkategorie"
msgctxt "help:cashbook.assetconf,fee_category:"
msgid "Category for fees when trading assets."
msgstr "Kategorie für Gebühren beim Handel mit Vermögenswerten."
msgctxt "field:cashbook.assetconf,dividend_category:"
msgid "Dividend category"
msgstr "Dividendenkategorie"
msgctxt "help:cashbook.assetconf,dividend_category:"
msgid "Category for dividend paid out."
msgstr "Kategorie für ausgezahlte Dividenden."
msgctxt "field:cashbook.assetconf,gainloss_book:"
msgid "Profit/Loss Cashbook"
msgstr "Gewinn/Verlust Kassenbuch"
msgctxt "help:cashbook.assetconf,gainloss_book:"
msgid "Profit and loss on sale of assets are recorded in the cash book."
msgstr "Gewinn und Verlust bei Verkauf von Vermögenswerten werden auf das Kassenbuch gebucht."

View file

@ -18,6 +18,14 @@ msgctxt "model:ir.message,text:msg_uomcat_mismatch"
msgid "Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s)." msgid "Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s)."
msgstr "Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s)." msgstr "Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s)."
msgctxt "model:ir.ui.menu,name:menu_assetconf"
msgid "Asset setting"
msgstr "Asset setting"
msgctxt "model:ir.action,name:act_assetconf_form"
msgid "Asset setting"
msgstr "Asset setting"
msgctxt "view:cashbook.book:" msgctxt "view:cashbook.book:"
msgid "Asset" msgid "Asset"
msgstr "Asset" msgstr "Asset"
@ -242,3 +250,31 @@ msgctxt "field:cashbook.recon,quantity_digits:"
msgid "Quantity Digits" msgid "Quantity Digits"
msgstr "Quantity Digits" msgstr "Quantity Digits"
msgctxt "field:cashbook.recon,quantity_uom:"
msgid "Symbol"
msgstr "Symbol"
msgctxt "model:cashbook.assetconf,name:"
msgid "Asset setting"
msgstr "Asset setting"
msgctxt "field:cashbook.assetconf,fee_category:"
msgid "Fee category"
msgstr "Fee category"
msgctxt "help:cashbook.assetconf,fee_category:"
msgid "Category for fees when trading assets."
msgstr "Category for fees when trading assets."
msgctxt "field:cashbook.assetconf,dividend_category:"
msgid "Dividend category"
msgstr "Dividend category"
msgctxt "help:cashbook.assetconf,dividend_category:"
msgid "Category for dividend paid out."
msgstr "Category for dividend paid out."
msgctxt "field:cashbook.assetconf,gainloss_book:"
msgid "Profit/Loss Cashbook"
msgstr "Profit/Loss Cashbook"

18
menu.xml Normal file
View file

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!-- 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. -->
<tryton>
<data>
<!-- menu: /Cashbook/Configuration/Asset seetting -->
<menuitem id="menu_assetconf" action="act_assetconf_form"
icon="tryton-settings"
parent="cashbook.menu_config" sequence="30"/>
<record model="ir.ui.menu-res.group" id="menu_assetconf-group_cashbook_admin">
<field name="menu" ref="menu_assetconf"/>
<field name="group" ref="cashbook.group_cashbook_admin"/>
</record>
</data>
</tryton>

View file

@ -6,6 +6,7 @@ import unittest
from trytond.modules.cashbook_investment.tests.test_book import CbInvTestCase from trytond.modules.cashbook_investment.tests.test_book import CbInvTestCase
from trytond.modules.cashbook_investment.tests.test_reconciliation import ReconTestCase from trytond.modules.cashbook_investment.tests.test_reconciliation import ReconTestCase
from trytond.modules.cashbook_investment.tests.test_yield import YieldTestCase
__all__ = ['suite'] __all__ = ['suite']
@ -14,6 +15,7 @@ __all__ = ['suite']
class CashbookInvestmentTestCase(\ class CashbookInvestmentTestCase(\
CbInvTestCase,\ CbInvTestCase,\
ReconTestCase,\ ReconTestCase,\
YieldTestCase,\
): ):
'Test cashbook-investment module' 'Test cashbook-investment module'
module = 'cashbook_investment' module = 'cashbook_investment'

215
tests/test_yield.py Normal file
View file

@ -0,0 +1,215 @@
# -*- 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 decimal import Decimal
from datetime import date
from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
class YieldTestCase(ModuleTestCase):
'Test yield calculation module'
module = 'cashbook_investment'
def prep_yield_config(self, fee, dividend, gainloss, company):
""" add config for yield-calculation
fee: name of fee-category,
dividend: name of fee-category,
gainloss: name of cashbook for gain/loss booking
"""
pool = Pool()
Category = pool.get('cashbook.category')
Cashbook = pool.get('cashbook.book')
AssetConf = pool.get('cashbook.assetconf')
fee_cat = Category.search([('name', '=', fee)])
if len(fee_cat) > 0:
fee_cat = fee_cat[0]
else :
fee_cat, = Category.create([{
'name': fee,
'company': company.id,
'cattype': 'out',
}])
dividend_cat = Category.search([('name', '=', dividend)])
if len(dividend_cat) > 0:
dividend_cat = dividend_cat[0]
else :
dividend_cat, = Category.create([{
'name': dividend,
'company': company.id,
'cattype': 'in',
}])
gainloss_book = Cashbook.search([('name', '=', gainloss)])
if len(gainloss_book) > 0:
gainloss_book = gainloss_book[0]
else :
types = self.prep_type()
gainloss_book, = Cashbook.create([{
'name': gainloss,
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
}])
as_cfg = None
with Transaction().set_context({
'company': company.id,
}):
as_cfg, = AssetConf.create([{
'fee_category': fee_cat.id,
'dividend_category': dividend_cat.id,
'gainloss_book': gainloss_book.id,
}])
self.assertEqual(as_cfg.fee_category.rec_name, 'Fee')
self.assertEqual(as_cfg.fee_category.cattype, 'out')
self.assertEqual(as_cfg.dividend_category.rec_name, 'Dividend')
self.assertEqual(as_cfg.dividend_category.cattype, 'in')
self.assertEqual(as_cfg.gainloss_book.rec_name,
'GainLoss | 0.00 usd | Open')
return as_cfg
@with_transaction()
def test_yield_config(self):
""" check config
"""
pool = Pool()
AssetConf = pool.get('cashbook.assetconf')
company = self.prep_company()
as_cfg = self.prep_yield_config('Fee', 'Dividend', 'GainLoss', company)
self.assertEqual(as_cfg.fee_category.rec_name, 'Fee')
self.assertEqual(as_cfg.dividend_category.rec_name, 'Dividend')
self.assertEqual(as_cfg.gainloss_book.rec_name, 'GainLoss | 0.00 usd | Open')
@with_transaction()
def test_yield_fee_dividend_gainloss(self):
""" add cashbook, categories, bookings for
fees, dididend...
"""
pool = Pool()
Cashbook = pool.get('cashbook.book')
BType = pool.get('cashbook.type')
Category = pool.get('cashbook.category')
Line = pool.get('cashbook.line')
company = self.prep_company()
as_cfg = self.prep_yield_config('Fee', 'Dividend', 'GainLoss', company)
type_depot = self.prep_type('Depot', 'D')
type_cash = self.prep_type('Cash', 'C')
BType.write(*[
[type_depot],
{
'feature': 'asset',
}])
asset = self.prep_asset_item(
company=company,
product = self.prep_asset_product(name='Product 1'))
self.assertEqual(asset.symbol, 'usd/u')
category_office, = Category.create([{
'name': 'Office',
'company': company.id,
}])
book_asset, = Cashbook.create([{
'name': 'Depot',
'btype': type_depot.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'asset': asset.id,
'quantity_uom': asset.uom.id,
'start_date': date(2022, 5, 1),
'lines': [('create', [{
'bookingtype': 'out',
'date': date(2022, 5, 1),
'amount': Decimal('2.0'),
'quantity': Decimal('0.0'),
'category': as_cfg.fee_category.id,
'description': 'Fee',
}, {
'bookingtype': 'in',
'date': date(2022, 5, 1),
'amount': Decimal('10.0'),
'quantity': Decimal('1.0'),
'category': as_cfg.dividend_category.id,
'description': 'reinvested dividend',
}])],
}])
# dividend, incoming + link to depot-account
book_cash, = Cashbook.create([{
'name': 'Cash',
'btype': type_cash.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
'lines': [('create', [{
'bookingtype': 'spin',
'date': date(2022, 5, 1),
'description': 'Dividend',
'splitlines': [('create', [{
'description': 'Dividend',
'splittype': 'cat',
'category': as_cfg.dividend_category.id,
'amount': Decimal('5.0'),
}, {
'description': 'Dividend',
'splittype': 'tr',
'booktransf': book_asset.id,
'amount': Decimal('0.0'),
'quantity': Decimal('0.0'),
}])],
}])],
}])
self.assertEqual(len(book_cash.lines), 1)
Line.wfcheck([book_cash.lines[0]])
self.assertEqual(book_cash.lines[0].rec_name,
'05/01/2022|Rev/Sp|5.00 usd|Dividend [-]')
self.assertEqual(book_cash.lines[0].reference, None)
self.assertEqual(len(book_cash.lines[0].references), 1)
self.assertEqual(book_cash.lines[0].references[0].rec_name,
'05/01/2022|to|0.00 usd|Dividend [Cash | 5.00 usd | Open]|0.0000 u')
self.assertEqual(book_asset.name, 'Depot')
self.assertEqual(book_asset.rec_name, 'Depot | 8.00 usd | Open | 1.0000 u')
self.assertEqual(book_asset.btype.rec_name, 'D - Depot')
self.assertEqual(book_asset.state, 'open')
self.assertEqual(book_asset.feature, 'asset')
self.assertEqual(len(book_asset.lines), 3)
# reference to dividend (1)
self.assertEqual(book_asset.lines[0].rec_name,
'05/01/2022|to|0.00 usd|Dividend [Cash | 5.00 usd | Open]|0.0000 u')
self.assertEqual(book_asset.lines[0].trade_fee, Decimal('0.0'))
self.assertEqual(book_asset.lines[0].asset_dividend, Decimal('5.0'))
self.assertEqual(book_asset.lines[0].asset_gainloss, Decimal('0.0'))
# fee payed from asset-account
self.assertEqual(book_asset.lines[1].rec_name,
'05/01/2022|Exp|-2.00 usd|Fee [Fee]|0.0000 u')
self.assertEqual(book_asset.lines[1].trade_fee, Decimal('-2.0'))
self.assertEqual(book_asset.lines[1].asset_dividend, Decimal('0.0'))
self.assertEqual(book_asset.lines[1].asset_gainloss, Decimal('0.0'))
# dividend (2) added to asset-account
self.assertEqual(book_asset.lines[2].rec_name,
'05/01/2022|Rev|10.00 usd|reinvested dividend [Dividend]|1.0000 u')
self.assertEqual(book_asset.lines[2].trade_fee, Decimal('0.0'))
self.assertEqual(book_asset.lines[2].asset_dividend, Decimal('10.0'))
self.assertEqual(book_asset.lines[2].asset_gainloss, Decimal('0.0'))
# end YieldTestCase

View file

@ -9,3 +9,5 @@ xml:
line.xml line.xml
reconciliation.xml reconciliation.xml
splitline.xml splitline.xml
assetsetting.xml
menu.xml

14
view/assetconf_form.xml Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!-- 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. -->
<form>
<label name="fee_category" />
<field name="fee_category"/>
<label name="dividend_category" />
<field name="dividend_category"/>
<label name="gainloss_book" />
<field name="gainloss_book"/>
</form>

View file

@ -34,6 +34,12 @@ full copyright notices and license terms. -->
<field name="diff_percent" xexpand="0"/> <field name="diff_percent" xexpand="0"/>
<label name="diff_percent" xalign="0.0" string="%" xexpand="1"/> <label name="diff_percent" xalign="0.0" string="%" xexpand="1"/>
</group> </group>
<label name="trade_fee"/>
<field name="trade_fee"/>
<label name="asset_dividend"/>
<field name="asset_dividend"/>
</page> </page>
</xpath> </xpath>