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:
parent
4a7ee23e2c
commit
59dfb94bee
7 changed files with 238 additions and 13 deletions
91
book.py
91
book.py
|
@ -11,8 +11,10 @@ from trytond.transaction import Transaction
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.report import Report
|
from trytond.report import Report
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from sql import Literal
|
||||||
from sql.aggregate import Sum
|
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
|
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,
|
balance = fields.Function(fields.Numeric(string='Balance', readonly=True,
|
||||||
digits=(16, Eval('currency_digits', 2)),
|
digits=(16, Eval('currency_digits', 2)),
|
||||||
depends=['currency_digits']), 'on_change_with_balance')
|
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={
|
states={
|
||||||
'readonly': Or(
|
'readonly': Or(
|
||||||
STATES2['readonly'],
|
STATES2['readonly'],
|
||||||
Bool(Eval('lines', [])),
|
Bool(Eval('lines', [])),
|
||||||
),
|
),
|
||||||
'invisible': STATES2['invisible'],
|
|
||||||
'required': ~STATES2['invisible'],
|
|
||||||
}, depends=DEPENDS2+['lines'])
|
}, depends=DEPENDS2+['lines'])
|
||||||
currency_digits = fields.Function(fields.Integer(string='Currency Digits',
|
currency_digits = fields.Function(fields.Integer(string='Currency Digits',
|
||||||
readonly=True), 'on_change_with_currency_digits')
|
readonly=True), 'on_change_with_currency_digits')
|
||||||
|
@ -255,36 +271,95 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
|
||||||
else:
|
else:
|
||||||
return 2
|
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')
|
@fields.depends('id')
|
||||||
def on_change_with_balance(self, name=None):
|
def on_change_with_balance(self, name=None):
|
||||||
""" compute balance
|
""" compute balance
|
||||||
"""
|
"""
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
Book2 = pool.get('cashbook.book')
|
Book2 = pool.get('cashbook.book')
|
||||||
|
Book3 = pool.get('cashbook.book')
|
||||||
Line = pool.get('cashbook.line')
|
Line = pool.get('cashbook.line')
|
||||||
|
Currency = pool.get('currency.currency')
|
||||||
|
|
||||||
tab_line = Line.__table__()
|
tab_line = Line.__table__()
|
||||||
|
tab_book = Book3.__table__()
|
||||||
cursor = Transaction().connection.cursor()
|
cursor = Transaction().connection.cursor()
|
||||||
|
|
||||||
|
# select cashbook-lines from current cashbook and below
|
||||||
line_query = Line.search([
|
line_query = Line.search([
|
||||||
('cashbook.id', 'in', Book2.search([
|
('cashbook.id', 'in', Book2.search([
|
||||||
('parent', 'child_of', [self.id]),
|
('parent', 'child_of', [self.id]),
|
||||||
], query=True)),
|
], query=True)),
|
||||||
], 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,
|
condition=tab_line.id==line_query.id,
|
||||||
|
).join(tab_book,
|
||||||
|
condition=tab_book.id==tab_line.cashbook,
|
||||||
).select(
|
).select(
|
||||||
Sum(tab_line.credit - tab_line.debit).as_('balance'),
|
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:
|
if self.id:
|
||||||
balance = Decimal('0.0')
|
|
||||||
cursor.execute(*query)
|
cursor.execute(*query)
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
|
balance = Decimal('0.0')
|
||||||
if result:
|
if result:
|
||||||
if result[0] is not None:
|
if result[0] is not None:
|
||||||
balance += result[0]
|
balance += result[0]
|
||||||
return balance
|
if self.currency:
|
||||||
|
return self.currency.compute(
|
||||||
|
self.currency, # from
|
||||||
|
balance,
|
||||||
|
self.company.currency # to
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ModelView.button
|
@ModelView.button
|
||||||
|
|
16
locale/de.po
16
locale/de.po
|
@ -554,6 +554,22 @@ msgctxt "field:cashbook.book,right:"
|
||||||
msgid "Right"
|
msgid "Right"
|
||||||
msgstr "Rechts"
|
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 #
|
# cashbook.split #
|
||||||
|
|
16
locale/en.po
16
locale/en.po
|
@ -518,6 +518,22 @@ msgctxt "field:cashbook.book,right:"
|
||||||
msgid "Right"
|
msgid "Right"
|
||||||
msgstr "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:"
|
msgctxt "model:cashbook.split,name:"
|
||||||
msgid "Split booking line"
|
msgid "Split booking line"
|
||||||
msgstr "Split booking line"
|
msgstr "Split booking line"
|
||||||
|
|
|
@ -56,6 +56,110 @@ class BookTestCase(ModuleTestCase):
|
||||||
self.assertEqual(book.state, 'open')
|
self.assertEqual(book.state, 'open')
|
||||||
self.assertEqual(book.state_string, '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()
|
@with_transaction()
|
||||||
def test_book_create_hierarchy(self):
|
def test_book_create_hierarchy(self):
|
||||||
""" create cashbook, hierarchical
|
""" create cashbook, hierarchical
|
||||||
|
|
|
@ -98,6 +98,13 @@ class ConfigTestCase(ModuleTestCase):
|
||||||
'rate': Decimal('1.05'),
|
'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)
|
return (usd, euro)
|
||||||
|
|
||||||
@with_transaction()
|
@with_transaction()
|
||||||
|
|
|
@ -15,10 +15,14 @@ full copyright notices and license terms. -->
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
|
<label name="balance"/>
|
||||||
|
<field name="balance" symbol="currency"/>
|
||||||
<label name="btype"/>
|
<label name="btype"/>
|
||||||
<field 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">
|
<notebook colspan="4">
|
||||||
<page name="reconciliations" string="Reconciliations" col="1">
|
<page name="reconciliations" string="Reconciliations" col="1">
|
||||||
|
@ -32,6 +36,11 @@ full copyright notices and license terms. -->
|
||||||
<field name="company"/>
|
<field name="company"/>
|
||||||
<label name="parent"/>
|
<label name="parent"/>
|
||||||
<field name="parent"/>
|
<field name="parent"/>
|
||||||
|
|
||||||
|
<label name="currency"/>
|
||||||
|
<field name="currency"/>
|
||||||
|
<newline/>
|
||||||
|
|
||||||
<field name="childs" colspan="4"/>
|
<field name="childs" colspan="4"/>
|
||||||
</page>
|
</page>
|
||||||
<page name="number_sequ" string="Amount and Numbering" col="4">
|
<page name="number_sequ" string="Amount and Numbering" col="4">
|
||||||
|
@ -42,8 +51,6 @@ full copyright notices and license terms. -->
|
||||||
|
|
||||||
<label name="start_date"/>
|
<label name="start_date"/>
|
||||||
<field name="start_date"/>
|
<field name="start_date"/>
|
||||||
<label name="currency"/>
|
|
||||||
<field name="currency"/>
|
|
||||||
</page>
|
</page>
|
||||||
<page id="pgperm" string="Owner and Authorizeds" col="4">
|
<page id="pgperm" string="Owner and Authorizeds" col="4">
|
||||||
<label name="owner"/>
|
<label name="owner"/>
|
||||||
|
|
|
@ -4,7 +4,7 @@ The COPYRIGHT file at the top level of this repository contains the
|
||||||
full copyright notices and license terms. -->
|
full copyright notices and license terms. -->
|
||||||
<tree>
|
<tree>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="balance" sum="Balance"/>
|
<field name="balance"/>
|
||||||
<field name="currency"/>
|
<field name="currency"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<field name="parent" tree_invisible="1"/>
|
<field name="parent" tree_invisible="1"/>
|
||||||
|
|
Loading…
Reference in a new issue