From 4e7d2c2ba92f6fc9a8443a5003d031441285050e Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Wed, 15 Feb 2023 22:34:52 +0100 Subject: [PATCH] add: field 'asset_gainloss' + searcher + test +todos --- line.py | 54 +++++++++++++++++++++++-------- tests/test_yield.py | 79 +++++++++++++++++++++++++++++++++++++++++++++ view/line_form.xml | 6 +++- 3 files changed, 125 insertions(+), 14 deletions(-) diff --git a/line.py b/line.py index 7990f65..e22433c 100644 --- a/line.py +++ b/line.py @@ -128,7 +128,7 @@ class Line(SecondUomMixin, metaclass=PoolMeta): states = { 'invisible': Eval('feature', '') != 'asset', }, depends=['currency_digits', 'feature']), - 'get_gainloss_data') + 'get_yield_data', searcher='search_asset_gainloss') @classmethod def get_gainloss_data_sql(cls): @@ -307,12 +307,24 @@ class Line(SecondUomMixin, metaclass=PoolMeta): ) return [('id', 'in', query)] + @classmethod + def search_asset_gainloss(cls, name, clause): + """ search for profit/loss + """ + Operator = fields.SQL_OPERATORS[clause[1]] + (tab_line, tab_query) = cls.get_gainloss_data_sql() + + query = tab_query.select( + tab_query.id, + where=Operator(tab_query.gainloss, clause[2]), + ) + return [('id', 'in', 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): @@ -323,19 +335,35 @@ class Line(SecondUomMixin, metaclass=PoolMeta): ).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), - } + # read fee, dividend + name_set = set({'trade_fee', 'asset_dividend'}).intersection(set(names)) + if len(name_set) > 0: + (tab_line, query) = cls.get_yield_data_sql() + 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), + } + for name in list(name_set): + result[name][record[0]] = values[name] + + # read asset_gainloss + if 'asset_gainloss' in names: + (tab_line, query) = cls.get_gainloss_data_sql() + 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]) + result['asset_gainloss'][record[0]] = quantize_val(record[1], line) - for name in names: - result[name][record[0]] = values[name] return result def get_rec_name(self, name): diff --git a/tests/test_yield.py b/tests/test_yield.py index 1591dea..b255a01 100644 --- a/tests/test_yield.py +++ b/tests/test_yield.py @@ -292,4 +292,83 @@ class YieldTestCase(ModuleTestCase): self.assertEqual(lines[0].rec_name, '05/01/2022|Rev/Sp|7.00 usd|Dividend [-]|0.0000 u') + # add counter-account for profit or loss of + # depot-account + book_gainloss, = Cashbook.create([{ + 'name': 'Profit-Loss', + 'btype': type_cash.id, + 'company': company.id, + 'currency': company.currency.id, + 'number_sequ': self.prep_sequence().id, + 'start_date': date(2022, 5, 1), + }]) + + # sale all shares with profit and fee + # buy: 23.50 + # sale: 32.90 (+40%) + # fee: 2.50 + # asset (buy amount): 23.50 + # booking: asset -> cash: - 30.40 + # asset -> (category) fee: - 2.50 + # asset <- gain-loss: 9.40 + # ------- + # 0.00 + self.assertEqual(book_asset.rec_name, 'Depot | 23.50 usd | Open | 3.0000 u') + self.assertEqual(book_gainloss.rec_name, 'Profit-Loss | 0.00 usd | Open') + lines = Line.create([{ + 'cashbook': book_asset.id, + 'date': date(2022, 5, 2), + 'bookingtype': 'spout', + 'description': 'all out', + 'splitlines': [('create', [{ + 'splittype': 'tr', + 'booktransf': book_cash.id, + 'description': 'sale with 40% profit', + 'quantity': Decimal('3.0'), + 'amount': Decimal('30.4'), + }, { + 'splittype': 'cat', + 'description': 'trade fee', + 'category': as_cfg.fee_category.id, + 'amount': Decimal('2.5'), + 'quantity': Decimal('0.0'), + }, { + 'splittype': 'tr', + 'booktransf': book_gainloss.id, + 'description': 'profit of sale', + 'amount': Decimal('-9.4'), + 'quantity': Decimal('0.0'), + }])], + }]) + + self.assertEqual(len(lines), 1) + self.assertEqual(lines[0].rec_name, + '05/02/2022|Exp/Sp|-23.50 usd|all out [-]|-3.0000 u') + Line.wfcheck(lines) + + self.assertEqual(lines[0].rec_name, + '05/02/2022|Exp/Sp|-23.50 usd|all out [-]|-3.0000 u') + self.assertEqual(len(lines[0].splitlines), 3) + self.assertEqual(lines[0].splitlines[0].rec_name, + 'Exp/Sp|30.40 usd|sale with 40% profit [Cash | 22.90 usd | Open]|3.0000 u') + self.assertEqual(lines[0].splitlines[1].rec_name, + 'Exp/Sp|2.50 usd|trade fee [Fee]|0.0000 u') + self.assertEqual(lines[0].splitlines[2].rec_name, + 'Exp/Sp|-9.40 usd|profit of sale [Profit-Loss | -9.40 usd | Open]|0.0000 u') + + print('\n# line:', lines[0].asset_gainloss, lines[0].asset_dividend, lines[0].trade_fee) + self.assertEqual(lines[0].asset_gainloss, Decimal('0.0')) + self.assertEqual(lines[0].asset_dividend, Decimal('0.0')) + self.assertEqual(lines[0].trade_fee, Decimal('0.0')) + + self.assertEqual(book_asset.rec_name, 'Depot | 0.00 usd | Open | 0.0000 u') + # negative amount on profit/loss-account means success + self.assertEqual(book_gainloss.rec_name, 'Profit-Loss | -9.40 usd | Open') + + # check searcher + lines = Line.search([('asset_gainloss', '=', Decimal('-9.4'))]) + self.assertEqual(len(lines), 1) + self.assertEqual(lines[0].rec_name, + 'Exp/Sp|-9.40 usd|profit of sale [Profit-Loss | -9.40 usd | Open]|0.0000 u') + # end YieldTestCase diff --git a/view/line_form.xml b/view/line_form.xml index 0e00fa3..016a1e0 100644 --- a/view/line_form.xml +++ b/view/line_form.xml @@ -24,7 +24,7 @@ full copyright notices and license terms. --> - +