book: view zeigt in listansicht bei unterkonten in fremdwährung

den korrekten wert,
book-form: feld für saldo in unternehmens-währung
This commit is contained in:
Frederik Jaeckel 2022-10-02 15:04:10 +02:00
parent 4a7ee23e2c
commit 59dfb94bee
7 changed files with 238 additions and 13 deletions

91
book.py
View file

@ -11,8 +11,10 @@ from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.report import Report
from decimal import Decimal
from sql import Literal
from sql.aggregate import Sum
from sql.conditionals import Case
from sql.conditionals import Case, Coalesce
from sql.functions import CurrentDate
from .model import order_name_hierarchical
@ -103,15 +105,29 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
balance = fields.Function(fields.Numeric(string='Balance', readonly=True,
digits=(16, Eval('currency_digits', 2)),
depends=['currency_digits']), 'on_change_with_balance')
currency = fields.Many2One(string='Currency',
model_name='currency.currency',
balance_ref = fields.Function(fields.Numeric(string='Balance (Ref.)',
help='Balance in company currency',
readonly=True, digits=(16, Eval('company_currency_digits', 2)),
states={
'invisible': ~Bool(Eval('company_currency')),
}, depends=['company_currency_digits', 'company_currency']),
'on_change_with_balance_ref')
company_currency = fields.Function(fields.Many2One(readonly=True,
string='Company Currency', states={'invisible': True},
model_name='currency.currency'),
'on_change_with_company_currency')
company_currency_digits = fields.Function(fields.Integer(
string='Currency Digits (Ref.)', readonly=True),
'on_change_with_currency_digits')
currency = fields.Many2One(string='Currency', select=True,
model_name='currency.currency', readonly=True,
states={
'readonly': Or(
STATES2['readonly'],
Bool(Eval('lines', [])),
),
'invisible': STATES2['invisible'],
'required': ~STATES2['invisible'],
}, depends=DEPENDS2+['lines'])
currency_digits = fields.Function(fields.Integer(string='Currency Digits',
readonly=True), 'on_change_with_currency_digits')
@ -255,36 +271,95 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
else:
return 2
@fields.depends('company', 'currency', 'btype')
def on_change_with_company_currency(self, name=None):
""" get company-currency if its different from current
cashbook-currency, disable if book is a view
"""
if self.company:
if self.currency:
if self.btype:
if self.company.currency.id != self.currency.id:
return self.company.currency.id
@fields.depends('id')
def on_change_with_balance(self, name=None):
""" compute balance
"""
pool = Pool()
Book2 = pool.get('cashbook.book')
Book3 = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
Currency = pool.get('currency.currency')
tab_line = Line.__table__()
tab_book = Book3.__table__()
cursor = Transaction().connection.cursor()
# select cashbook-lines from current cashbook and below
line_query = Line.search([
('cashbook.id', 'in', Book2.search([
('parent', 'child_of', [self.id]),
], query=True)),
], query=True)
query = line_query.join(tab_line,
# sum lines by currency
bal_by_currency = line_query.join(tab_line,
condition=tab_line.id==line_query.id,
).join(tab_book,
condition=tab_book.id==tab_line.cashbook,
).select(
Sum(tab_line.credit - tab_line.debit).as_('balance'),
tab_book.currency,
group_by=[tab_book.currency],
)
if self.id:
total = Decimal('0.0')
cursor.execute(*bal_by_currency)
balance_lines = cursor.fetchall()
for line in balance_lines:
(balance, id_currency) = line
total += Currency.compute(
Currency(id_currency), # from
balance,
self.currency, # to
)
return total
@fields.depends('company', 'currency', 'id', 'btype')
def on_change_with_balance_ref(self, name=None):
""" balance converted to company-currency
"""
pool = Pool()
Line = pool.get('cashbook.line')
tab_line = Line.__table__()
cursor = Transaction().connection.cursor()
if self.btype is None:
return None
query = tab_line.select(
Sum(tab_line.credit - tab_line.debit),
where = tab_line.cashbook == self.id,
)
if self.id:
balance = Decimal('0.0')
cursor.execute(*query)
result = cursor.fetchone()
balance = Decimal('0.0')
if result:
if result[0] is not None:
balance += result[0]
return balance
if self.currency:
return self.currency.compute(
self.currency, # from
balance,
self.company.currency # to
)
@classmethod
@ModelView.button

View file

@ -554,6 +554,22 @@ msgctxt "field:cashbook.book,right:"
msgid "Right"
msgstr "Rechts"
msgctxt "field:cashbook.book,balance_ref:"
msgid "Balance (Ref.)"
msgstr "Saldo (Ref.)"
msgctxt "help:cashbook.book,balance_ref:"
msgid "Balance in company currency"
msgstr "Saldo in der Unternehmenswährung"
msgctxt "field:cashbook.book,company_currency:"
msgid "Company Currency"
msgstr "Unternehmenswährung"
msgctxt "field:cashbook.book,company_currency_digits:"
msgid "Currency Digits (Ref.)"
msgstr "Nachkommastellen Währung (Ref.)"
##################
# cashbook.split #

View file

@ -518,6 +518,22 @@ msgctxt "field:cashbook.book,right:"
msgid "Right"
msgstr "Right"
msgctxt "field:cashbook.book,balance_ref:"
msgid "Balance (Ref.)"
msgstr "Balance (Ref.)"
msgctxt "help:cashbook.book,balance_ref:"
msgid "Balance in company currency"
msgstr "Balance in company currency"
msgctxt "field:cashbook.book,company_currency:"
msgid "Company Currency"
msgstr "Company Currency"
msgctxt "field:cashbook.book,company_currency_digits:"
msgid "Currency Digits (Ref.)"
msgstr "Currency Digits (Ref.)"
msgctxt "model:cashbook.split,name:"
msgid "Split booking line"
msgstr "Split booking line"

View file

@ -56,6 +56,110 @@ class BookTestCase(ModuleTestCase):
self.assertEqual(book.state, 'open')
self.assertEqual(book.state_string, 'Open')
@with_transaction()
def test_book_create_2nd_currency(self):
""" create cashbook, in 2nd currency, check balance-fields
"""
pool = Pool()
Book = pool.get('cashbook.book')
types = self.prep_type()
company = self.prep_company()
# add EURO, set company-currency to EURO
(usd, euro) = self.prep_2nd_currency(company)
category = self.prep_category(cattype='in')
self.assertEqual(company.currency.rec_name, 'Euro')
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
'company': company.id,
'currency': usd.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
'lines': [('create', [{
'date': date(2022, 5, 5),
'description': 'Amount in USD',
'bookingtype': 'in',
'category': category.id,
'amount': Decimal('10.0'),
}])],
}])
with Transaction().set_context({
'date': date(2022, 5, 5),
}):
self.assertEqual(book.rec_name, 'Book 1 | 10.00 usd | Open')
self.assertEqual(book.currency.rec_name, 'usd')
self.assertEqual(book.currency.rate, Decimal('1.05'))
self.assertEqual(book.company_currency.rec_name, 'Euro')
self.assertEqual(book.company_currency.rate, Decimal('1.0'))
self.assertEqual(book.balance, Decimal('10.0'))
self.assertEqual(book.balance_ref, Decimal('9.52'))
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].rec_name,
'05/05/2022|Rev|10.00 usd|Amount in USD [Cat1]')
@with_transaction()
def test_book_create_2nd_currency_hierarchical(self):
""" create cashbook-hierarchy, in 2nd currency,
check balance-fields
"""
pool = Pool()
Book = pool.get('cashbook.book')
types = self.prep_type()
company = self.prep_company()
# add EURO, set company-currency to EURO
(usd, euro) = self.prep_2nd_currency(company)
category = self.prep_category(cattype='in')
self.assertEqual(company.currency.rec_name, 'Euro')
book, = Book.create([{
'name': 'Book 1',
'company': company.id,
'currency': euro.id,
'childs': [('create', [{
'name': 'Book 2',
'btype': types.id,
'company': company.id,
'currency': usd.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
'lines': [('create', [{
'date': date(2022, 5, 5),
'description': 'Amount in USD',
'bookingtype': 'in',
'category': category.id,
'amount': Decimal('10.0'),
}])],
}])],
}])
with Transaction().set_context({
'date': date(2022, 5, 5),
}):
self.assertEqual(book.rec_name, 'Book 1')
self.assertEqual(book.currency.rec_name, 'Euro')
self.assertEqual(book.currency.rate, Decimal('1.0'))
self.assertEqual(book.company_currency, None)
self.assertEqual(book.balance, Decimal('9.52'))
self.assertEqual(book.balance_ref, None)
self.assertEqual(len(book.lines), 0)
self.assertEqual(len(book.childs), 1)
self.assertEqual(book.childs[0].rec_name, 'Book 1/Book 2 | 10.00 usd | Open')
self.assertEqual(book.childs[0].currency.rec_name, 'usd')
self.assertEqual(book.childs[0].currency.rate, Decimal('1.05'))
self.assertEqual(book.childs[0].company_currency.rec_name, 'Euro')
self.assertEqual(book.childs[0].balance, Decimal('10.0'))
self.assertEqual(book.childs[0].balance_ref, Decimal('9.52'))
self.assertEqual(len(book.childs[0].lines), 1)
@with_transaction()
def test_book_create_hierarchy(self):
""" create cashbook, hierarchical

View file

@ -98,6 +98,13 @@ class ConfigTestCase(ModuleTestCase):
'rate': Decimal('1.05'),
}])
# delete unwanted rates
usd_1 = CurrencyRate.search([
('currency.id', '=', usd.id),
('date', '!=', date(2022, 5, 2)),
])
CurrencyRate.delete(usd_1)
return (usd, euro)
@with_transaction()

View file

@ -15,10 +15,14 @@ full copyright notices and license terms. -->
</group>
</group>
<label name="balance"/>
<field name="balance" symbol="currency"/>
<label name="btype"/>
<field name="btype"/>
<label name="balance"/>
<field name="balance"/>
<label name="balance_ref"/>
<field name="balance_ref" symbol="company_currency"/>
<newline/>
<notebook colspan="4">
<page name="reconciliations" string="Reconciliations" col="1">
@ -32,6 +36,11 @@ full copyright notices and license terms. -->
<field name="company"/>
<label name="parent"/>
<field name="parent"/>
<label name="currency"/>
<field name="currency"/>
<newline/>
<field name="childs" colspan="4"/>
</page>
<page name="number_sequ" string="Amount and Numbering" col="4">
@ -42,8 +51,6 @@ full copyright notices and license terms. -->
<label name="start_date"/>
<field name="start_date"/>
<label name="currency"/>
<field name="currency"/>
</page>
<page id="pgperm" string="Owner and Authorizeds" col="4">
<label name="owner"/>

View file

@ -4,7 +4,7 @@ The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
<tree>
<field name="name"/>
<field name="balance" sum="Balance"/>
<field name="balance"/>
<field name="currency"/>
<field name="state"/>
<field name="parent" tree_invisible="1"/>