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)):

View file

@ -12,6 +12,13 @@ full copyright notices and license terms. -->
<field name="priority" eval="10"/>
<field name="name">book_list</field>
</record>
<record model="ir.ui.view" id="book_view_tree">
<field name="model">cashbook.book</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="field_childs">childs</field>
<field name="name">book_tree</field>
</record>
<record model="ir.ui.view" id="book_view_form">
<field name="model">cashbook.book</field>
<field name="type">form</field>
@ -19,7 +26,7 @@ full copyright notices and license terms. -->
<field name="name">book_form</field>
</record>
<!-- action view-->
<!-- action view - list -->
<record model="ir.action.act_window" id="act_book_view">
<field name="name">Cashbook</field>
<field name="res_model">cashbook.book</field>
@ -35,6 +42,23 @@ full copyright notices and license terms. -->
<field name="act_window" ref="act_book_view"/>
</record>
<!-- action view - tree -->
<record model="ir.action.act_window" id="act_book_tree">
<field name="name">Cashbook</field>
<field name="res_model">cashbook.book</field>
<field name="domain" eval="[('parent', '=', None)]" pyson="1"/>
</record>
<record model="ir.action.act_window.view" id="act_book_tree-1">
<field name="sequence" eval="10"/>
<field name="view" ref="book_view_tree"/>
<field name="act_window" ref="act_book_tree"/>
</record>
<record model="ir.action.act_window.view" id="act_book_tree-2">
<field name="sequence" eval="20"/>
<field name="view" ref="book_view_form"/>
<field name="act_window" ref="act_book_tree"/>
</record>
<!-- permission -->
<!-- anon: deny all -->
<record model="ir.model.access" id="access_book-anon">
@ -251,18 +275,24 @@ full copyright notices and license terms. -->
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
</record>
<record model="ir.model.field.access" id="fa_book-start_balance-anon">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'start_balance')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
</record>
<record model="ir.model.field.access" id="fa_book-currency-anon">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'currency')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
</record>
<record model="ir.model.field.access" id="fa_book-parent-anon">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'parent')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
</record>
<record model="ir.model.field.access" id="fa_book-childs-anon">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'childs')]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
</record>
<!-- field-access - group_cashbook_admin -->
<record model="ir.model.field.access" id="fa_book-company-group_cashbook_admin">
@ -335,16 +365,23 @@ full copyright notices and license terms. -->
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
</record>
<record model="ir.model.field.access" id="fa_book-start_balance-group_cashbook_admin">
<record model="ir.model.field.access" id="fa_book-currency-group_cashbook_admin">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'start_balance')]"/>
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'currency')]"/>
<field name="group" ref="group_cashbook_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
</record>
<record model="ir.model.field.access" id="fa_book-currency-group_cashbook_admin">
<record model="ir.model.field.access" id="fa_book-parent-group_cashbook_admin">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'currency')]"/>
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'parent')]"/>
<field name="group" ref="group_cashbook_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
</record>
<record model="ir.model.field.access" id="fa_book-childs-group_cashbook_admin">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'childs')]"/>
<field name="group" ref="group_cashbook_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
@ -421,16 +458,23 @@ full copyright notices and license terms. -->
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
</record>
<record model="ir.model.field.access" id="fa_book-start_balance-group_cashbook">
<record model="ir.model.field.access" id="fa_book-currency-group_cashbook">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'start_balance')]"/>
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'currency')]"/>
<field name="group" ref="group_cashbook"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
</record>
<record model="ir.model.field.access" id="fa_book-currency-group_cashbook">
<record model="ir.model.field.access" id="fa_book-parent-group_cashbook">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'currency')]"/>
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'parent')]"/>
<field name="group" ref="group_cashbook"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
</record>
<record model="ir.model.field.access" id="fa_book-childs-group_cashbook">
<field name="field"
search="[('model.model', '=', 'cashbook.book'), ('name', '=', 'childs')]"/>
<field name="group" ref="group_cashbook"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>

View file

@ -51,7 +51,8 @@ class Line(Workflow, ModelSQL, ModelView):
__name__ = 'cashbook.line'
cashbook = fields.Many2One(string='Cashbook', required=True, select=True,
model_name='cashbook.book', ondelete='CASCADE', readonly=True)
model_name='cashbook.book', ondelete='CASCADE', readonly=True,
domain=[('btype', '!=', None)])
date = fields.Date(string='Date', required=True, select=True,
states=STATES, depends=DEPENDS)
month = fields.Function(fields.Integer(string='Month', readonly=True),
@ -607,8 +608,8 @@ class Line(Workflow, ModelSQL, ModelView):
return 2
@fields.depends('id', 'date', 'cashbook', \
'_parent_cashbook.start_balance', '_parent_cashbook.id',\
'reconciliation', '_parent_reconciliation.start_amount',
'_parent_cashbook.id', 'reconciliation', \
'_parent_reconciliation.start_amount',\
'_parent_reconciliation.state')
def on_change_with_balance(self, name=None):
""" compute balance until current line, with current sort order,
@ -646,7 +647,7 @@ class Line(Workflow, ModelSQL, ModelView):
query = [
('cashbook.id', '=', self.cashbook.id),
]
balance = self.cashbook.start_balance
balance = Decimal('0.0')
# get existing reconciliation, starting before current line
# this will speed up calculation of by-line-balance

View file

@ -70,10 +70,6 @@ msgctxt "model:ir.message,text:msg_category_type_not_like_parent"
msgid "The type of the current category '%(catname)s' must be equal to the type of the parent category '%(parentname)s'."
msgstr "Der Typ der aktuellen Kategorie '%(catname)s' muß gleich dem Typ der übergeordneten Kategorie '%(parentname)s' sein."
msgctxt "model:ir.message,text:msg_book_err_startamount_with_lines"
msgid "The initial amount of the cash book '%(bookname)s' cannot be changed because it already contains bookings."
msgstr "Der Anfangsbetrag des Kassenbuchs '%(bookname)s' kann nicht geändert werden, da es bereits Buchungen enthält."
msgctxt "model:ir.message,text:msg_line_deny_recon_by_state"
msgid "For reconciliation, the line '%(recname)s' must be in the status 'Check' or 'Done'."
msgstr "Für die Abstimmung muss die Zeile '%(recname)s' im Status 'Prüfen' oder 'Fertig' sein."
@ -258,6 +254,10 @@ msgctxt "model:ir.ui.menu,name:menu_booklist"
msgid "Cashbook"
msgstr "Kassenbuch"
msgctxt "model:ir.ui.menu,name:menu_booktree"
msgid "Cashbook"
msgstr "Kassenbuch"
msgctxt "model:ir.ui.menu,name:menu_open_lines"
msgid "Open Cashbook"
msgstr "Kassenbuch öffnen"
@ -286,6 +286,10 @@ msgctxt "model:ir.action,name:act_book_view"
msgid "Cashbook"
msgstr "Kassenbuch"
msgctxt "model:ir.action,name:act_book_tree"
msgid "Cashbook"
msgstr "Kassenbuch"
msgctxt "model:ir.action,name:act_type_view"
msgid "Cashbook Type"
msgstr "Kassenbuchtyp"
@ -418,6 +422,10 @@ msgctxt "view:cashbook.book:"
msgid "General Information"
msgstr "Allgemein"
msgctxt "view:cashbook.book:"
msgid "Amount and Numbering"
msgstr "Betrag und Nummerierung"
msgctxt "view:cashbook.book:"
msgid "Balance"
msgstr "Saldo"
@ -434,6 +442,10 @@ msgctxt "field:cashbook.book,btype:"
msgid "Type"
msgstr "Typ"
msgctxt "help:cashbook.book,btype:"
msgid "A cash book with type can contain postings. Without type is a view."
msgstr "Ein Kassenbuch mit Typ kann Buchungen enthalten. Ohne Typ ist eine Sicht."
msgctxt "field:cashbook.book,state:"
msgid "State"
msgstr "Status"
@ -482,10 +494,6 @@ msgctxt "field:cashbook.book,currency_digits:"
msgid "Currency Digits"
msgstr "Nachkommastellen Währung"
msgctxt "field:cashbook.book,start_balance:"
msgid "Initial Amount"
msgstr "Anfangsbetrag"
msgctxt "field:cashbook.book,start_date:"
msgid "Initial Date"
msgstr "Anfangsdatum"
@ -518,6 +526,22 @@ msgctxt "help:cashbook.book,number_atcheck:"
msgid "The numbering of the lines is done in the step Check. If the check mark is inactive, this happens with Done."
msgstr "Die Nummerierung der Zeilen wird beim Schritt 'Prüfen' erledigt. Bei inaktivem Häkchen passiert dies erst bei 'Fertig'."
msgctxt "field:cashbook.book,parent:"
msgid "Parent"
msgstr "Übergeordnet"
msgctxt "field:cashbook.book,childs:"
msgid "Children"
msgstr "Untergeordnet"
msgctxt "field:cashbook.book,left:"
msgid "Left"
msgstr "Links"
msgctxt "field:cashbook.book,right:"
msgid "Right"
msgstr "Rechts"
##################
# cashbook.split #

View file

@ -66,10 +66,6 @@ msgctxt "model:ir.message,text:msg_category_type_not_like_parent"
msgid "The type of the current category '%(catname)s' must be equal to the type of the parent category '%(parentname)s'."
msgstr "The type of the current category '%(catname)s' must be equal to the type of the parent category '%(parentname)s'."
msgctxt "model:ir.message,text:msg_book_err_startamount_with_lines"
msgid "The initial amount of the cash book '%(bookname)s' cannot be changed because it already contains bookings."
msgstr "The initial amount of the cash book '%(bookname)s' cannot be changed because it already contains bookings."
msgctxt "model:ir.message,text:msg_line_deny_recon_by_state"
msgid "For reconciliation, the line '%(recname)s' must be in the status 'Check' or 'Done'."
msgstr "For reconciliation, the line '%(recname)s' must be in the status 'Check' or 'Done'."
@ -242,6 +238,10 @@ msgctxt "model:ir.ui.menu,name:menu_booklist"
msgid "Cashbook"
msgstr "Cashbook"
msgctxt "model:ir.ui.menu,name:menu_booktree"
msgid "Cashbook"
msgstr "Cashbook"
msgctxt "model:ir.ui.menu,name:menu_open_lines"
msgid "Open Cashbook"
msgstr "Open Cashbook"
@ -266,6 +266,10 @@ msgctxt "model:ir.action,name:act_book_view"
msgid "Cashbook"
msgstr "Cashbook"
msgctxt "model:ir.action,name:act_book_tree"
msgid "Cashbook"
msgstr "Cashbook"
msgctxt "model:ir.action,name:act_type_view"
msgid "Cashbook Type"
msgstr "Cashbook Type"
@ -382,6 +386,10 @@ msgctxt "view:cashbook.book:"
msgid "General Information"
msgstr "General Information"
msgctxt "view:cashbook.book:"
msgid "Amount and Numbering"
msgstr "Amount and Numbering"
msgctxt "view:cashbook.book:"
msgid "Balance"
msgstr "Balance"
@ -398,6 +406,10 @@ msgctxt "field:cashbook.book,btype:"
msgid "Type"
msgstr "Type"
msgctxt "help:cashbook.book,btype:"
msgid "A cash book with type can contain postings. Without type is a view."
msgstr "A cash book with type can contain postings. Without type is a view."
msgctxt "field:cashbook.book,state:"
msgid "State"
msgstr "State"
@ -446,10 +458,6 @@ msgctxt "field:cashbook.book,currency_digits:"
msgid "Currency Digits"
msgstr "Currency Digits"
msgctxt "field:cashbook.book,start_balance:"
msgid "Initial Amount"
msgstr "Initial Amount"
msgctxt "field:cashbook.book,start_date:"
msgid "Initial Date"
msgstr "Initial Date"
@ -482,6 +490,22 @@ msgctxt "help:cashbook.book,number_atcheck:"
msgid "The numbering of the lines is done in the step Check. If the check mark is inactive, this happens with Done."
msgstr "The numbering of the lines is done in the step Check. If the check mark is inactive, this happens with Done."
msgctxt "field:cashbook.book,parent:"
msgid "Parent"
msgstr "Parent"
msgctxt "field:cashbook.book,childs:"
msgid "Children"
msgstr "Children"
msgctxt "field:cashbook.book,left:"
msgid "Left"
msgstr "Left"
msgctxt "field:cashbook.book,right:"
msgid "Right"
msgstr "Right"
msgctxt "model:cashbook.split,name:"
msgid "Split booking line"
msgstr "Split booking line"

View file

@ -83,9 +83,21 @@ full copyright notices and license terms. -->
</record>
<!-- menu: /Cashbook/Cashbook -->
<menuitem id="menu_booktree" action="act_book_tree"
icon="tryton-tree"
parent="menu_cashbook" sequence="40"/>
<record model="ir.ui.menu-res.group" id="menu_booktree-group_cashbook">
<field name="menu" ref="menu_booktree"/>
<field name="group" ref="group_cashbook"/>
</record>
<record model="ir.ui.menu-res.group" id="menu_booktree-group_cashbook_admin">
<field name="menu" ref="menu_booktree"/>
<field name="group" ref="group_cashbook_admin"/>
</record>
<!-- menu: /Cashbook/Cashbook/Cashbook -->
<menuitem id="menu_booklist" action="act_book_view"
icon="tryton-list"
parent="menu_cashbook" sequence="40"/>
parent="menu_booktree" sequence="10"/>
<record model="ir.ui.menu-res.group" id="menu_booklist-group_cashbook">
<field name="menu" ref="menu_booklist"/>
<field name="group" ref="group_cashbook"/>

View file

@ -53,9 +53,6 @@ full copyright notices and license terms. -->
<record model="ir.message" id="msg_category_type_not_like_parent">
<field name="text">The type of the current category '%(catname)s' must be equal to the type of the parent category '%(parentname)s'.</field>
</record>
<record model="ir.message" id="msg_book_err_startamount_with_lines">
<field name="text">The initial amount of the cash book '%(bookname)s' cannot be changed because it already contains bookings.</field>
</record>
<record model="ir.message" id="msg_line_deny_recon_by_state">
<field name="text">For reconciliation, the line '%(recname)s' must be in the status 'Check' or 'Done'.</field>
</record>

View file

@ -226,7 +226,7 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
))
values['start_amount'] = reconciliation.predecessor.end_amount
else :
values['start_amount'] = reconciliation.cashbook.start_balance
values['start_amount'] = Decimal('0.0')
values['end_amount'] = values['start_amount']
# add 'checked'-lines to reconciliation

View file

@ -51,10 +51,37 @@ class BookTestCase(ModuleTestCase):
'number_sequ': self.prep_sequence().id,
}])
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')
@with_transaction()
def test_book_create_hierarchy(self):
""" create cashbook, hierarchical
"""
pool = Pool()
Book = pool.get('cashbook.book')
types = self.prep_type()
company = self.prep_company()
book, = Book.create([{
'name': 'Level 1',
'btype': None,
'company': company.id,
'childs': [('create', [{
'name': 'Level 2',
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
}])],
}])
self.assertEqual(book.name, 'Level 1')
self.assertEqual(book.rec_name, 'Level 1')
self.assertEqual(len(book.childs), 1)
self.assertEqual(book.childs[0].rec_name, 'Level 1/Level 2 | 0.00 usd | Open')
@with_transaction()
def test_book_deny_delete_open(self):
""" create cashbook, add lines, try to delete in state 'open'
@ -225,62 +252,6 @@ class BookTestCase(ModuleTestCase):
},
])
@with_transaction()
def test_book_deny_update_start_amount(self):
""" create cashbook, add lines, update start-amount
"""
pool = Pool()
Book = pool.get('cashbook.book')
types = self.prep_type()
company = self.prep_company()
category = self.prep_category(cattype='in')
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
}])
self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.start_balance, Decimal('0.0'))
self.assertEqual(book.rec_name, 'Book 1 | 0.00 usd | Open')
Book.write(*[
[book],
{
'start_balance': Decimal('1.0'),
}])
self.assertEqual(book.start_balance, Decimal('1.0'))
self.assertEqual(book.balance, Decimal('1.0'))
Book.write(*[
[book],
{
'lines': [('create', [{
'amount': Decimal('2.0'),
'description': 'Test',
'category': category.id,
'bookingtype': 'in',
'party': party.id,
}])],
}])
self.assertEqual(book.start_balance, Decimal('1.0'))
self.assertEqual(book.balance, Decimal('3.0'))
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].balance, Decimal('3.0'))
self.assertRaisesRegex(UserError,
"The initial amount of the cash book 'Fridas book | 3.00 usd | Open' cannot be changed because it already contains bookings.",
Book.write,
*[
[book],
{
'start_balance': Decimal('1.5'),
},
])
@with_transaction()
def test_book_permission_owner(self):
""" create book + 2x users, add users to group, check access

View file

@ -39,7 +39,6 @@ class BookingWizardTestCase(ModuleTestCase):
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 1, 1),
'start_balance': Decimal('0.0'),
}])
party, = Party.create([{
@ -114,7 +113,6 @@ class BookingWizardTestCase(ModuleTestCase):
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 1, 1),
'start_balance': Decimal('0.0'),
}, {
'name': 'Bank',
'btype': types.id,
@ -122,7 +120,6 @@ class BookingWizardTestCase(ModuleTestCase):
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 1, 1),
'start_balance': Decimal('0.0'),
}])
party, = Party.create([{

View file

@ -574,6 +574,36 @@ class LineTestCase(ModuleTestCase):
self.assertEqual(book.lines[2].rec_name, '05/01/2022|Rev/Sp|1.00 usd|Text 3 [-]')
self.assertEqual(book.lines[2].state, 'edit')
@with_transaction()
def test_line_to_non_type_book(self):
""" create cashbook w/o type
"""
pool = Pool()
Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
category = self.prep_category(cattype='in')
company = self.prep_company()
party = self.prep_party()
book, = Book.create([{
'name': 'Book 1',
'btype': None,
'company': company.id,
}])
self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.state, 'open')
self.assertRaisesRegex(UserError,
'The value for field "Cashbook" in "Cashbook Line" is not valid according to its domain.',
Line.create,
[{
'cashbook': book.id,
'date': date(2022, 5, 1),
'category': category.id,
'bookingtype': 'in',
'amount': Decimal('0.0'),
}])
@with_transaction()
def test_line_create_check_deny_write(self):
""" create cashbook + line, 'close' book, write to line

View file

@ -221,7 +221,6 @@ class ReconTestCase(ModuleTestCase):
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'start_balance': Decimal('12.50'),
'start_date': date(2022, 5, 1),
'number_sequ': self.prep_sequence().id,
'reconciliations': [('create', [{
@ -234,7 +233,7 @@ class ReconTestCase(ModuleTestCase):
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
Reconciliation.wfcheck(list(book.reconciliations))
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 12.50 usd - 12.50 usd [0]')
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 0.00 usd [0]')
@with_transaction()
def test_recon_set_start_amount_by_predecessor(self):
@ -254,7 +253,6 @@ class ReconTestCase(ModuleTestCase):
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'start_balance': Decimal('12.50'),
'start_date': date(2022, 5, 1),
'number_sequ': self.prep_sequence().id,
'reconciliations': [('create', [{
@ -287,7 +285,7 @@ class ReconTestCase(ModuleTestCase):
Reconciliation.wfcheck(list(book.reconciliations))
self.assertEqual(book.reconciliations[0].state, 'check')
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 12.50 usd - 24.50 usd [2]')
self.assertEqual(book.reconciliations[0].rec_name, '05/01/2022 - 05/31/2022 | 0.00 usd - 12.00 usd [2]')
Reconciliation.wfdone(list(book.reconciliations))
self.assertEqual(book.reconciliations[0].state, 'done')
@ -298,7 +296,7 @@ class ReconTestCase(ModuleTestCase):
}])
self.assertEqual(recons[0].rec_name, '05/31/2022 - 06/30/2022 | 0.00 usd - 0.00 usd [0]')
Reconciliation.wfcheck(recons)
self.assertEqual(recons[0].rec_name, '05/31/2022 - 06/30/2022 | 24.50 usd - 24.50 usd [0]')
self.assertEqual(recons[0].rec_name, '05/31/2022 - 06/30/2022 | 12.00 usd - 12.00 usd [0]')
@with_transaction()
def test_recon_predecessor_done(self):

View file

@ -15,29 +15,32 @@ full copyright notices and license terms. -->
</group>
</group>
<label name="btype"/>
<field name="btype"/>
<label name="balance"/>
<field name="balance"/>
<newline/>
<notebook colspan="4">
<page id="pgrecon" string="Reconciliations" col="1">
<page name="reconciliations" string="Reconciliations" col="1">
<field name="reconciliations"/>
</page>
<page id="pggeneral" string="General Information" col="4">
<label name="company"/>
<field name="company"/>
<label name="parent"/>
<field name="parent"/>
<field name="childs" colspan="4"/>
</page>
<page name="number_sequ" string="Amount and Numbering" col="4">
<label name="number_sequ"/>
<field name="number_sequ"/>
<label name="number_atcheck"/>
<field name="number_atcheck"/>
<label name="btype"/>
<field name="btype"/>
<label name="currency"/>
<field name="currency"/>
<label name="start_balance"/>
<field name="start_balance"/>
<label name="start_date"/>
<field name="start_date"/>
<label name="currency"/>
<field name="currency"/>
<label id="phaccount" colspan="2" string=" "/>
</page>

View file

@ -5,7 +5,6 @@ full copyright notices and license terms. -->
<tree>
<field name="name"/>
<field name="btype"/>
<field name="start_balance"/>
<field name="balance" sum="Balance"/>
<field name="currency"/>
<field name="owner"/>

14
view/book_tree.xml Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!-- 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. -->
<tree>
<field name="name"/>
<field name="btype"/>
<field name="balance" sum="Balance"/>
<field name="currency"/>
<field name="owner"/>
<field name="state"/>
<field name="parent" tree_invisible="1"/>
<field name="childs" tree_invisible="1"/>
</tree>

View file

@ -13,13 +13,12 @@ full copyright notices and license terms. -->
<field name="description" colspan="5"/>
<notebook colspan="6">
<page string="General Information" id="general" col="6">
<page string="General Information" id="general" col="4">
<label name="company"/>
<field name="company"/>
<label name="parent"/>
<field name="parent"/>
<newline/>
<field name="childs" colspan="6"/>
<field name="childs" colspan="4"/>
</page>
</notebook>