From 70416dbc12ea7e3f35ddc060a9baf47a8a4d604a Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Thu, 22 Dec 2022 00:32:26 +0100 Subject: [PATCH] =?UTF-8?q?book/line:=20felder=20f=C3=BCr=20quantity,=20et?= =?UTF-8?q?c.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .hgignore | 3 + __init__.py | 6 ++ book.py | 77 ++++++++++++++++++ book.xml | 15 ++++ line.py | 69 ++++++++++++++++ line.xml | 15 ++++ locale/de.po | 59 ++++++++++++++ locale/en.po | 44 +++++++++++ message.xml | 13 +++ tests/__init__.py | 24 ++++++ tests/test_book.py | 191 +++++++++++++++++++++++++++++++++++++++++++++ tryton.cfg | 4 + types.py | 21 +++++ view/book_form.xml | 20 +++++ view/line_form.xml | 22 ++++++ 15 files changed, 583 insertions(+) create mode 100644 .hgignore create mode 100644 book.py create mode 100644 book.xml create mode 100644 line.py create mode 100644 line.xml create mode 100644 locale/de.po create mode 100644 locale/en.po create mode 100644 message.xml create mode 100644 tests/__init__.py create mode 100644 tests/test_book.py create mode 100644 types.py create mode 100644 view/book_form.xml create mode 100644 view/line_form.xml diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..1b85cd9 --- /dev/null +++ b/.hgignore @@ -0,0 +1,3 @@ +syntax: glob +__pycache__/* +locale/convert_de2en.py diff --git a/__init__.py b/__init__.py index fe669db..d7417b1 100644 --- a/__init__.py +++ b/__init__.py @@ -4,7 +4,13 @@ # full copyright notices and license terms. from trytond.pool import Pool +from .types import Type +from .book import Book +from .line import Line def register(): Pool.register( + Type, + Book, + Line, module='cashbook_investment', type_='model') diff --git a/book.py b/book.py new file mode 100644 index 0000000..98371c7 --- /dev/null +++ b/book.py @@ -0,0 +1,77 @@ +# -*- 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.model import fields +from trytond.exceptions import UserError +from trytond.pool import PoolMeta +from trytond.pyson import Eval, Or, Len +from trytond.modules.cashbook.book import STATES2, DEPENDS2 + + +class Book(metaclass=PoolMeta): + __name__ = 'cashbook.book' + + asset = fields.Many2One(string='Asset', + model_name='investment.asset', ondelete='RESTRICT', + states={ + 'required': Eval('feature', '') == 'asset', + 'invisible': Eval('feature', '') != 'asset', + 'readonly': Or( + STATES2['readonly'], + Len(Eval('lines')) > 0, + ), + }, depends=DEPENDS2+['feature', 'lines']) + quantity_digits = fields.Integer(string='Digits', + help='Quantity Digits', + domain=[ + ('quantity_digits', '>=', 0), + ('quantity_digits', '<=', 6), + ], + states={ + 'required': Eval('feature', '') == 'asset', + 'invisible': Eval('feature', '') != 'asset', + 'readonly': Or( + STATES2['readonly'], + Len(Eval('lines')) > 0, + ), + }, depends=DEPENDS2+['feature', 'lines']) + asset_uomcat = fields.Function(fields.Many2One(string='UOM Category', + readonly=True, model_name='product.uom.category', + states={'invisible': True}), 'on_change_with_asset_uomcat') + quantity_uom = fields.Many2One(string='UOM', + model_name='product.uom', ondelete='RESTRICT', + domain=[ + ('category.id', '=', Eval('asset_uomcat', -1)), + ], + states={ + 'required': Eval('feature', '') == 'asset', + 'invisible': Eval('feature', '') != 'asset', + 'readonly': Or( + STATES2['readonly'], + Len(Eval('lines')) > 0, + ), + }, depends=DEPENDS2+['feature', 'lines', 'asset_uomcat']) + + @fields.depends('asset', 'quantity_uom') + def on_change_asset(self): + """ get uom from asset + """ + if self.asset: + self.quantity_uom = self.asset.uom.id + + @classmethod + def default_quantity_digits(cls): + """ default: 4 + """ + return 4 + + @fields.depends('asset', '_parent_asset.uom') + def on_change_with_asset_uomcat(self, name=None): + """ get uom-category of asset + """ + if self.asset: + return self.asset.uom.category.id + +# end Book diff --git a/book.xml b/book.xml new file mode 100644 index 0000000..12806b1 --- /dev/null +++ b/book.xml @@ -0,0 +1,15 @@ + + + + + + + cashbook.book + + book_form + + + + diff --git a/line.py b/line.py new file mode 100644 index 0000000..9fbdab6 --- /dev/null +++ b/line.py @@ -0,0 +1,69 @@ +# -*- 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 trytond.model import fields +from trytond.pool import PoolMeta +from trytond.pyson import Eval, Or, If +from trytond.modules.cashbook.line import STATES, DEPENDS + + +class Line(metaclass=PoolMeta): + __name__ = 'cashbook.line' + + quantity = fields.Numeric(string='Quantity', + digits=(16, Eval('quantity_digits', 4)), + states={ + 'required': Eval('feature', '') == 'asset', + 'invisible': Eval('feature', '') != 'asset', + 'readonly': Or( + STATES['readonly'], + Eval('bookingtype', '').in_(['spin', 'spout']), + ), + }, depends=DEPENDS+['feature', 'quantity_digits', 'bookingtype']) + quantity_digits = fields.Function(fields.Integer(string='Digits', + readonly=True, states={'invisible': True}), + 'on_change_with_quantity_digits') + quantity_uom = fields.Function(fields.Many2One(string='Symbol', + readonly=True, model_name='product.uom'), + 'on_change_with_quantity_symbol') + asset_rate = fields.Function(fields.Numeric(string='Rate', + readonly=True, + digits=(16, If( + Eval('currency_digits', 2) > Eval('quantity_digits', 2), + Eval('currency_digits', 2), Eval('quantity_digits', 2)))), + 'on_change_with_asset_rate') + #asset_ratesymbol = fields. + + @fields.depends('quantity', 'amount', 'currency_digits', 'quantity_digits') + def on_change_with_asset_rate(self, name=None): + """ get rate + """ + if (self.quantity is None) or (self.amount is None): + return + digit = max( + self.currency_digits if self.currency_digits is not None else 2, + self.quantity_digits if self.quantity_digits is not None else 4) + if self.quantity != Decimal('0.0'): + return ( + self.amount / self.quantity + ).quantize(Decimal(str(1/10**digit))) + + @fields.depends('cashbook', '_parent_cashbook.quantity_uom') + def on_change_with_quantity_symbol(self, name=None): + """ get quantity-symbol of asset + """ + if self.cashbook: + return self.cashbook.quantity_uom.id + + @fields.depends('cashbook', '_parent_cashbook.quantity_digits') + def on_change_with_quantity_digits(self, name=None): + """ get digits from cashbook + """ + if self.cashbook: + return self.cashbook.quantity_digits + return 4 + +# end LineContext diff --git a/line.xml b/line.xml new file mode 100644 index 0000000..83df0ea --- /dev/null +++ b/line.xml @@ -0,0 +1,15 @@ + + + + + + + cashbook.line + + line_form + + + + diff --git a/locale/de.po b/locale/de.po new file mode 100644 index 0000000..2175463 --- /dev/null +++ b/locale/de.po @@ -0,0 +1,59 @@ +# +msgid "" +msgstr "Content-Type: text/plain; charset=utf-8\n" + + +############## +# ir.message # +############## +msgctxt "model:ir.message,text:msg_btype_asset" +msgid "Asset" +msgstr "Vermögenswert" + + +################# +# cashbook.book # +################# +msgctxt "view:cashbook.book:" +msgid "Asset" +msgstr "Vermögenswert" + +msgctxt "field:cashbook.book,asset:" +msgid "Asset" +msgstr "Vermögenswert" + +msgctxt "field:cashbook.book,quantity_digits:" +msgid "Digits" +msgstr "Dezimalstellen" + +msgctxt "help:cashbook.book,quantity_digits:" +msgid "Quantity Digits" +msgstr "Dezimalstellen für Anzahl" + +msgctxt "help:cashbook.book,asset_uomcat:" +msgid "UOM Category" +msgstr "Einheitenkategorie" + +msgctxt "help:cashbook.book,quantity_uom:" +msgid "UOM" +msgstr "Einheit" + + +################# +# cashbook.line # +################# +msgctxt "field:cashbook.line,quantity_digits:" +msgid "Digits" +msgstr "Dezimalstellen" + +msgctxt "field:cashbook.line,quantity:" +msgid "Quantity" +msgstr "Anzahl" + +msgctxt "field:cashbook.line,quantity_symbol:" +msgid "Symbol" +msgstr "Symbol" + +msgctxt "field:cashbook.line,asset_rate:" +msgid "Rate" +msgstr "Kurs" diff --git a/locale/en.po b/locale/en.po new file mode 100644 index 0000000..ff8880b --- /dev/null +++ b/locale/en.po @@ -0,0 +1,44 @@ +# +msgid "" +msgstr "Content-Type: text/plain; charset=utf-8\n" + +msgctxt "model:ir.message,text:msg_btype_asset" +msgid "Asset" +msgstr "Asset" + +msgctxt "view:cashbook.book:" +msgid "Asset" +msgstr "Asset" + +msgctxt "field:cashbook.book,asset:" +msgid "Asset" +msgstr "Asset" + +msgctxt "field:cashbook.book,quantity_digits:" +msgid "Digits" +msgstr "Digits" + +msgctxt "help:cashbook.book,quantity_digits:" +msgid "Quantity Digits" +msgstr "Quantity Digits" + +msgctxt "help:cashbook.book,asset_uomcat:" +msgid "UOM Category" +msgstr "UOM Category" + +msgctxt "help:cashbook.book,quantity_uom:" +msgid "UOM" +msgstr "UOM" + +msgctxt "field:cashbook.line,quantity_digits:" +msgid "Digits" +msgstr "Digits" + +msgctxt "field:cashbook.line,quantity:" +msgid "Quantity" +msgstr "Quantity" + +msgctxt "field:cashbook.line,quantity_symbol:" +msgid "Symbol" +msgstr "Symbol" + diff --git a/message.xml b/message.xml new file mode 100644 index 0000000..96ddc9f --- /dev/null +++ b/message.xml @@ -0,0 +1,13 @@ + + + + + + + Asset + + + + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..51d7cde --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,24 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. + +import trytond.tests.test_tryton +import unittest + +from trytond.modules.cashbook_investment.tests.test_book import CbInvTestCase + + +__all__ = ['suite'] + + +class CashbookInvestmentTestCase(\ + CbInvTestCase,\ + ): + 'Test cashbook-investment module' + module = 'cashbook_investment' + +# end CashbookInvestmentTestCase + +def suite(): + suite = trytond.tests.test_tryton.suite() + suite.addTests(unittest.TestLoader().loadTestsFromTestCase(CashbookInvestmentTestCase)) + return suite diff --git a/tests/test_book.py b/tests/test_book.py new file mode 100644 index 0000000..660de27 --- /dev/null +++ b/tests/test_book.py @@ -0,0 +1,191 @@ +# -*- 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.tests.test_tryton import ModuleTestCase, with_transaction +from trytond.pool import Pool +from trytond.transaction import Transaction +from trytond.exceptions import UserError +from trytond.modules.cashbook.tests import CashbookTestCase +from trytond.modules.investment.tests import InvestmentTestCase +from datetime import date +from decimal import Decimal + + +class CbInvTestCase(CashbookTestCase, InvestmentTestCase): + 'Test cashbook-investment module' + module = 'cashbook_investment' + + @with_transaction() + def test_assetbook_create(self): + """ create cashbook, set 'btype' to asset + """ + pool = Pool() + Book = pool.get('cashbook.book') + BType = pool.get('cashbook.type') + + types = self.prep_type() + company = self.prep_company() + book, = Book.create([{ + 'name': 'Book 1', + 'btype': types.id, + 'company': company.id, + 'currency': company.currency.id, + 'number_sequ': self.prep_sequence().id, + }]) + + BType.write(*[ + [types], + { + 'feature': 'asset', + }]) + + self.assertEqual(book.name, 'Book 1') + self.assertEqual(book.rec_name, 'Book 1 | 0.00 usd | Open') + self.assertEqual(book.btype.rec_name, 'CAS - Cash') + self.assertEqual(book.state, 'open') + self.assertEqual(book.state_string, 'Open') + self.assertEqual(book.feature, 'asset') + self.assertEqual(book.quantity_digits, 4) + + @with_transaction() + def test_assetbook_create_line(self): + """ create cashbook, add line + """ + pool = Pool() + Book = pool.get('cashbook.book') + BType = pool.get('cashbook.type') + + types = self.prep_type() + BType.write(*[ + [types], + { + 'feature': 'asset', + }]) + category = self.prep_category(cattype='in') + + company = self.prep_company() + party = self.prep_party() + asset = self.prep_asset_item( + company=company, + product = self.prep_asset_product(name='Product 1')) + self.assertEqual(asset.symbol, 'usd/u') + + book, = Book.create([{ + 'start_date': date(2022, 4, 1), + 'name': 'Book 1', + 'btype': types.id, + 'company': company.id, + 'currency': company.currency.id, + 'number_sequ': self.prep_sequence().id, + 'asset': asset.id, + 'quantity_uom': asset.uom.id, + 'quantity_digits': 3, + 'lines': [('create', [{ + 'date': date(2022, 5, 1), + 'description': 'Text 1', + 'category': category.id, + 'bookingtype': 'in', + 'amount': Decimal('2.5'), + 'party': party.id, + 'quantity': Decimal('1.453'), + }], + )], + }]) + + self.assertEqual(book.name, 'Book 1') + self.assertEqual(book.rec_name, 'Book 1 | 2.50 usd | Open') + self.assertEqual(book.state, 'open') + self.assertEqual(book.feature, 'asset') + self.assertEqual(book.quantity_digits, 3) + self.assertEqual(book.balance_all, Decimal('2.5')) + self.assertEqual(len(book.lines), 1) + self.assertEqual(book.lines[0].amount, Decimal('2.5')) + self.assertEqual(book.lines[0].quantity, Decimal('1.453')) + self.assertEqual(book.lines[0].quantity_digits, 3) + self.assertEqual(book.lines[0].quantity_symbol, 'u') + + @with_transaction() + def test_assetbook_book_uom(self): + """ check default auf uom + """ + pool = Pool() + Book = pool.get('cashbook.book') + BType = pool.get('cashbook.type') + + company = self.prep_company() + types = self.prep_type() + BType.write(*[ + [types], + { + 'feature': 'asset', + 'name': 'Asset', + 'short': 'A', + }]) + + asset = self.prep_asset_item( + company=company, + product = self.prep_asset_product(name='Product 1')) + self.assertEqual(asset.symbol, 'usd/u') + + book = Book( + asset = asset, + quantity_uom = None, + ) + self.assertEqual(book.quantity_uom, None) + book.on_change_asset() + self.assertEqual(book.quantity_uom.rec_name, 'Unit') + + @with_transaction() + def test_assetbook_book_with_asset(self): + """ create cashbook, set 'btype' to asset + """ + pool = Pool() + Book = pool.get('cashbook.book') + BType = pool.get('cashbook.type') + + company = self.prep_company() + types = self.prep_type() + BType.write(*[ + [types], + { + 'feature': 'asset', + 'name': 'Asset', + 'short': 'A', + }]) + + asset = self.prep_asset_item( + company=company, + product = self.prep_asset_product(name='Product 1')) + self.assertEqual(asset.symbol, 'usd/u') + + book, = Book.create([{ + 'name': 'Book 1', + 'btype': types.id, + 'company': company.id, + 'currency': company.currency.id, + 'number_sequ': self.prep_sequence().id, + 'asset': asset.id, + 'quantity_uom': asset.uom.id, + }]) + + self.assertEqual(book.name, 'Book 1') + self.assertEqual(book.rec_name, 'Book 1 | 0.00 usd | Open') + self.assertEqual(book.btype.rec_name, 'A - Asset') + self.assertEqual(book.state, 'open') + self.assertEqual(book.feature, 'asset') + self.assertEqual(book.asset.rec_name, 'Product 1 | - usd/u | -') + self.assertEqual(book.quantity_uom.rec_name, 'Unit') + + self.assertRaisesRegex(UserError, + 'A value is required for field "Asset" in "Cashbook".', + Book.write, + *[ + [book], + { + 'asset': None, + } + ]) + +# end CbInvTestCase diff --git a/tryton.cfg b/tryton.cfg index fceac5a..4ba0023 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -2,4 +2,8 @@ version=6.0.0 depends: cashbook + investment xml: + message.xml + book.xml + line.xml diff --git a/types.py b/types.py new file mode 100644 index 0000000..27f83f7 --- /dev/null +++ b/types.py @@ -0,0 +1,21 @@ +# -*- 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.i18n import gettext +from trytond.pool import PoolMeta + + +class Type(metaclass=PoolMeta): + __name__ = 'cashbook.type' + + @classmethod + def get_sel_feature(cls): + """ get feature-modes + """ + l1 = super(Type, cls).get_sel_feature() + l1.append(('asset', gettext('cashbook_investment.msg_btype_asset'))) + return l1 + +# end Type diff --git a/view/book_form.xml b/view/book_form.xml new file mode 100644 index 0000000..7a679d5 --- /dev/null +++ b/view/book_form.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/view/line_form.xml b/view/line_form.xml new file mode 100644 index 0000000..97e9d0b --- /dev/null +++ b/view/line_form.xml @@ -0,0 +1,22 @@ + + + + + + + +