book: hierarchie + test

book: Feld 'start_balance' entfernt
This commit is contained in:
Frederik Jaeckel 2022-09-15 23:49:54 +02:00
parent e10616e847
commit a2e7f192f8
16 changed files with 319 additions and 168 deletions

140
book.py
View file

@ -3,7 +3,7 @@
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
from trytond.model import Workflow, ModelView, ModelSQL, fields, Check
from trytond.model import Workflow, ModelView, ModelSQL, fields, Check, tree
from trytond.pyson import Eval, Or, Bool, Id
from trytond.exceptions import UserError
from trytond.i18n import gettext
@ -20,6 +20,16 @@ STATES = {
}
DEPENDS=['state']
# states in case of 'btype'!=None
STATES2 = {
'readonly': Or(
Eval('state', '') != 'open',
~Bool(Eval('btype')),
),
'invisible': ~Bool(Eval('btype')),
}
DEPENDS2 = ['state', 'btype']
sel_state_book = [
('open', 'Open'),
('closed', 'Closed'),
@ -27,7 +37,7 @@ sel_state_book = [
]
class Book(Workflow, ModelSQL, ModelView):
class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
'Cashbook'
__name__ = 'cashbook.book'
@ -35,9 +45,15 @@ class Book(Workflow, ModelSQL, ModelView):
required=True, ondelete="RESTRICT")
name = fields.Char(string='Name', required=True,
states=STATES, depends=DEPENDS)
btype = fields.Many2One(string='Type', required=True,
btype = fields.Many2One(string='Type',
help='A cash book with type can contain postings. Without type is a view.',
model_name='cashbook.type', ondelete='RESTRICT',
states=STATES, depends=DEPENDS)
states={
'readonly': Or(
STATES['readonly'],
Bool(Eval('lines')),
),
}, depends=DEPENDS+['lines'])
owner = fields.Many2One(string='Owner', required=True, select=True,
model_name='res.user', ondelete='SET NULL',
states=STATES, depends=DEPENDS)
@ -54,8 +70,8 @@ class Book(Workflow, ModelSQL, ModelView):
states=STATES, depends=DEPENDS)
reconciliations = fields.One2Many(string='Reconciliations',
field='cashbook', model_name='cashbook.recon',
states=STATES, depends=DEPENDS)
number_sequ = fields.Many2One(string='Line numbering', required=True,
states=STATES2, depends=DEPENDS2)
number_sequ = fields.Many2One(string='Line numbering',
help='Number sequence for numbering of the cash book lines.',
model_name='ir.sequence',
domain=[
@ -65,41 +81,56 @@ class Book(Workflow, ModelSQL, ModelView):
('company', '=', Eval('company', -1)),
],
],
states=STATES, depends=DEPENDS+['company'])
states={
'readonly': STATES2['readonly'],
'required': Bool(Eval('btype')),
}, depends=DEPENDS2+['company'])
number_atcheck = fields.Boolean(string="number when 'Checking'",
help="The numbering of the lines is done in the step Check. If the check mark is inactive, this happens with Done.")
start_date = fields.Date(string='Initial Date', required=True,
help="The numbering of the lines is done in the step Check. If the check mark is inactive, this happens with Done.",
states=STATES2, depends=DEPENDS2)
start_date = fields.Date(string='Initial Date',
states={
'readonly': Or(
STATES['readonly'],
STATES2['readonly'],
Bool(Eval('lines')),
),
}, depends=DEPENDS+['lines'])
start_balance = fields.Numeric(string='Initial Amount', required=True,
digits=(16, Eval('currency_digits', 2)),
states={
'readonly': Or(
STATES['readonly'],
Bool(Eval('lines')),
),
}, depends=DEPENDS+['lines', 'currency_digits'])
'invisible': STATES2['invisible'],
'required': Bool(Eval('btype')),
}, depends=DEPENDS2+['lines'])
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', required=True,
currency = fields.Many2One(string='Currency',
model_name='currency.currency',
states={
'readonly': Or(
STATES['readonly'],
STATES2['readonly'],
Bool(Eval('lines', [])),
),
}, depends=DEPENDS+['lines'])
'invisible': STATES2['invisible'],
'required': Bool(Eval('btype')),
}, depends=DEPENDS2+['lines'])
currency_digits = fields.Function(fields.Integer(string='Currency Digits',
readonly=True), 'on_change_with_currency_digits')
state = fields.Selection(string='State', required=True,
readonly=True, selection=sel_state_book)
state_string = state.translated('state')
parent = fields.Many2One(string="Parent",
model_name='cashbook.book', ondelete='RESTRICT',
left='left', right='right')
childs = fields.One2Many(string='Children', field='parent',
model_name='cashbook.book')
left = fields.Integer(string='Left', required=True, select=True)
right = fields.Integer(string='Right', required=True, select=True)
@classmethod
def __register__(cls, module_name):
super(Book, cls).__register__(module_name)
table = cls.__table_handler__(module_name)
table.drop_column('start_balance')
@classmethod
def __setup__(cls):
super(Book, cls).__setup__()
@ -131,16 +162,18 @@ class Book(Workflow, ModelSQL, ModelView):
},
})
@staticmethod
def default_left():
return 0
@staticmethod
def default_right():
return 0
@classmethod
def default_number_atcheck(cls):
return True
@classmethod
def default_start_balance(cls):
""" zero
"""
return Decimal('0.0')
@classmethod
def default_currency(cls):
""" currency of company
@ -193,12 +226,15 @@ class Book(Workflow, ModelSQL, ModelView):
def get_rec_name(self, name):
""" name, balance, state
"""
return '%(name)s | %(balance)s %(symbol)s | %(state)s' % {
'name': self.name or '-',
'balance': Report.format_number(self.balance or 0.0, None),
'symbol': getattr(self.currency, 'symbol', '-'),
'state': self.state_string,
}
recname = super(Book, self).get_rec_name(name)
if self.btype:
return '%(name)s | %(balance)s %(symbol)s | %(state)s' % {
'name': recname or '-',
'balance': Report.format_number(self.balance or 0.0, None),
'symbol': getattr(self.currency, 'symbol', '-'),
'state': self.state_string,
}
return recname
@fields.depends('currency')
def on_change_with_currency_digits(self, name=None):
@ -209,28 +245,36 @@ class Book(Workflow, ModelSQL, ModelView):
else:
return 2
@fields.depends('id', 'start_balance')
@fields.depends('id')
def on_change_with_balance(self, name=None):
""" compute balance
"""
Line = Pool().get('cashbook.line')
pool = Pool()
Book2 = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
tab_line = Line.__table__()
cursor = Transaction().connection.cursor()
query = tab_line.select(
line_query = Line.search([
('cashbook.id', 'in', Book2.search([
('parent', 'child_of', [self.id]),
], query=True)),
], query=True)
query = line_query.join(tab_line,
condition=tab_line.id==line_query.id,
).select(
Sum(tab_line.credit - tab_line.debit).as_('balance'),
group_by=[tab_line.cashbook],
where=tab_line.cashbook == self.id
)
if self.id:
if self.start_balance is not None:
balance = self.start_balance
cursor.execute(*query)
result = cursor.fetchone()
if result:
balance = Decimal('0.0')
cursor.execute(*query)
result = cursor.fetchone()
if result:
if result[0] is not None:
balance += result[0]
return balance
return balance
@classmethod
@ModelView.button
@ -263,12 +307,6 @@ class Book(Workflow, ModelSQL, ModelView):
actions = iter(args)
for books, values in zip(actions, actions):
for book in books:
if 'start_balance' in values.keys():
if len(book.lines) > 0:
raise UserError(gettext(
'cashbook.msg_book_err_startamount_with_lines',
bookname = book.rec_name,
))
if book.state != 'open':
# allow state-update, if its the only action
if not (('state' in values.keys()) and (len(values.keys()) == 1)):