diff --git a/book.py b/book.py
index a9a2add..38fa020 100644
--- a/book.py
+++ b/book.py
@@ -45,6 +45,8 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
required=True, ondelete="RESTRICT")
name = fields.Char(string='Name', required=True,
states=STATES, depends=DEPENDS)
+ description = fields.Text(string='Description',
+ states=STATES, depends=DEPENDS)
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',
@@ -307,6 +309,15 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
actions = iter(args)
for books, values in zip(actions, actions):
for book in books:
+ # deny btype-->None if lines not empty
+ if 'btype' in values.keys():
+ if (values['btype'] is None) and (len(book.lines) > 0):
+ raise UserError(gettext(
+ 'cashbook.msg_book_btype_with_lines',
+ cbname = book.rec_name,
+ numlines = len(book.lines),
+ ))
+
if book.state != 'open':
# allow state-update, if its the only action
if not (('state' in values.keys()) and (len(values.keys()) == 1)):
diff --git a/configuration.py b/configuration.py
index e8de3b6..2dc986e 100644
--- a/configuration.py
+++ b/configuration.py
@@ -17,7 +17,8 @@ field_catnamelong = fields.Boolean(string='Category: Show long name',
help='Shows the long name of the category in the Category field of a cash book line.')
field_defbook = fields.Many2One(string='Default Cashbook',
help='The default cashbook is selected when you open the booking wizard.',
- model_name='cashbook.book', ondelete='SET NULL')
+ model_name='cashbook.book', ondelete='SET NULL',
+ domain=[('btype', '!=', None)])
class Configuration(ModelSingleton, ModelSQL, ModelView, UserMultiValueMixin):
diff --git a/line.py b/line.py
index 59b778f..db402e9 100644
--- a/line.py
+++ b/line.py
@@ -931,6 +931,7 @@ class LineContext(ModelView):
cashbook = fields.Many2One(string='Cashbook', required=True,
model_name='cashbook.book',
+ domain=[('btype', '!=', None)],
states={
'readonly': Eval('num_cashbook', 0) < 2,
}, depends=['num_cashbook'])
@@ -993,7 +994,7 @@ class LineContext(ModelView):
with Transaction().set_context({
'_check_access': True,
}):
- return CashBook.search_count([])
+ return CashBook.search_count([('btype', '!=', None)])
@classmethod
def default_done(cls):
diff --git a/locale/de.po b/locale/de.po
index 6075046..ba68660 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -146,6 +146,10 @@ msgctxt "model:ir.message,text:msg_line_invalid_category"
msgid "The category of the booking line '%(recname)s' does not match the posting type '%(booktype)s'."
msgstr "Die Kategorie der Buchungszeile '%(recname)s' paßt nicht zum Buchungstyp '%(booktype)s'."
+msgctxt "model:ir.message,text:msg_book_btype_with_lines"
+msgid "The type cannot be deleted on the cash book '%(cbname)s' because it still contains %(numlines)s lines."
+msgstr "Der Typ kann am Kassenbuch '%(cbname)s' nicht gelöscht werden, da es noch %(numlines)s Zeilen enthält."
+
#############
# res.group #
@@ -434,10 +438,18 @@ msgctxt "view:cashbook.book:"
msgid "Reconciliations"
msgstr "Abstimmungen"
+msgctxt "view:cashbook.book:"
+msgid "Description"
+msgstr "Beschreibung"
+
msgctxt "field:cashbook.book,name:"
msgid "Name"
msgstr "Name"
+msgctxt "field:cashbook.book,description:"
+msgid "Description"
+msgstr "Beschreibung"
+
msgctxt "field:cashbook.book,btype:"
msgid "Type"
msgstr "Typ"
diff --git a/locale/en.po b/locale/en.po
index 912ff90..5d58001 100644
--- a/locale/en.po
+++ b/locale/en.po
@@ -142,6 +142,10 @@ msgctxt "model:ir.message,text:msg_line_invalid_category"
msgid "The category of the booking line '%(recname)s' does not match the posting type '%(booktype)s'."
msgstr "The category of the booking line '%(recname)s' does not match the posting type '%(booktype)s'."
+msgctxt "model:ir.message,text:msg_book_btype_with_lines"
+msgid "The type cannot be deleted on the cash book '%(cbname)s' because it still contains %(numlines)s lines."
+msgstr "The type cannot be deleted on the cash book '%(cbname)s' because it still contains %(numlines)s lines."
+
msgctxt "model:res.group,name:group_cashbook"
msgid "Cashbook"
msgstr "Cashbook"
@@ -398,10 +402,18 @@ msgctxt "view:cashbook.book:"
msgid "Reconciliations"
msgstr "Reconciliations"
+msgctxt "view:cashbook.book:"
+msgid "Description"
+msgstr "Description"
+
msgctxt "field:cashbook.book,name:"
msgid "Name"
msgstr "Name"
+msgctxt "field:cashbook.book,description:"
+msgid "Description"
+msgstr "Description"
+
msgctxt "field:cashbook.book,btype:"
msgid "Type"
msgstr "Type"
diff --git a/message.xml b/message.xml
index 3946a30..14bc840 100644
--- a/message.xml
+++ b/message.xml
@@ -110,6 +110,9 @@ full copyright notices and license terms. -->
The category of the booking line '%(recname)s' does not match the posting type '%(booktype)s'.
+
+ The type cannot be deleted on the cash book '%(cbname)s' because it still contains %(numlines)s lines.
+
diff --git a/tests/test_book.py b/tests/test_book.py
index c5be24e..67fea04 100644
--- a/tests/test_book.py
+++ b/tests/test_book.py
@@ -117,6 +117,62 @@ class BookTestCase(ModuleTestCase):
Book.delete,
[book])
+ @with_transaction()
+ def test_book_deny_btype_set_none(self):
+ """ create cashbook, add lines,
+ try to set btype to None with lines
+ """
+ pool = Pool()
+ Book = pool.get('cashbook.book')
+
+ types = self.prep_type()
+ category = self.prep_category(cattype='in')
+ company = self.prep_company()
+ 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,
+ 'start_date': date(2022, 5, 1),
+ 'lines': [('create', [{
+ 'date': date(2022, 5, 1),
+ 'description': 'test 1',
+ 'category': category.id,
+ 'bookingtype': 'in',
+ 'amount': Decimal('1.0'),
+ 'party': party.id,
+ }])],
+ }])
+ self.assertEqual(book.name, 'Book 1')
+ self.assertEqual(book.btype.rec_name, 'CAS - Cash')
+
+ self.assertRaisesRegex(UserError,
+ "The type cannot be deleted on the cash book 'Book 1 | 1.00 usd | Open' because it still contains 1 lines.",
+ Book.write,
+ *[
+ [book],
+ {
+ 'btype': None,
+ },
+ ])
+
+ Book.write(*[
+ [book],
+ {
+ 'lines': [('delete', [book.lines[0].id])],
+ }])
+ self.assertEqual(len(book.lines), 0)
+ self.assertEqual(book.btype.rec_name, 'CAS - Cash')
+
+ Book.write(*[
+ [book],
+ {
+ 'btype': None,
+ }])
+ self.assertEqual(book.btype, None)
+
@with_transaction()
def test_book_deny_delete_closed(self):
""" create cashbook, add lines, try to delete in state 'closed'
diff --git a/view/book_form.xml b/view/book_form.xml
index c47d19a..d2ffaad 100644
--- a/view/book_form.xml
+++ b/view/book_form.xml
@@ -24,6 +24,9 @@ full copyright notices and license terms. -->
+
+
+
diff --git a/view/book_list.xml b/view/book_list.xml
index bb85e16..087927c 100644
--- a/view/book_list.xml
+++ b/view/book_list.xml
@@ -3,10 +3,8 @@
The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
-
-
+
-
diff --git a/view/book_tree.xml b/view/book_tree.xml
index a09b734..32a14b6 100644
--- a/view/book_tree.xml
+++ b/view/book_tree.xml
@@ -4,10 +4,8 @@ The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
-
-
diff --git a/wizard_booking.py b/wizard_booking.py
index 0c84545..4a383d1 100644
--- a/wizard_booking.py
+++ b/wizard_booking.py
@@ -20,7 +20,7 @@ class EnterBookingStart(ModelView):
__name__ = 'cashbook.enterbooking.start'
cashbook = fields.Many2One(string='Cashbook', model_name='cashbook.book',
- domain=[('id', 'in', Eval('cashbooks', []))],
+ domain=[('id', 'in', Eval('cashbooks', [])), ('btype', '!=', None)],
depends=['cashbooks'], required=True)
cashbooks = fields.One2Many(string='Cashbooks', field=None,
model_name='cashbook.book', readonly=True,
@@ -137,6 +137,7 @@ class EnterBookingWizard(Wizard):
result = {
'cashbooks': [x.id for x in Cashbook.search([
('state', '=', 'open'),
+ ('btype', '!=', None),
('owner.id', '=', Transaction().user),
])],
'bookingtype': getattr(self.start, 'bookingtype', 'out'),
diff --git a/wizard_openline.py b/wizard_openline.py
index fa4256c..2c76ea0 100644
--- a/wizard_openline.py
+++ b/wizard_openline.py
@@ -16,7 +16,7 @@ class OpenCashBookStart(ModelView):
__name__ = 'cashbook.open_lines.start'
cashbook = fields.Many2One(string='Cashbook', model_name='cashbook.book',
- required=True)
+ required=True, domain=[('btype', '!=', None)])
checked = fields.Boolean(string='Checked', help="Show cashbook lines in Checked-state.")
done = fields.Boolean(string='Done', help="Show cashbook lines in Done-state")
date_from = fields.Date(string='Start Date')
@@ -54,7 +54,7 @@ class OpenCashBook(Wizard):
with Transaction().set_context({
'_check_access': True,
}):
- books = Book.search([])
+ books = Book.search([('btype', '!=', None)])
if len(books) == 1:
return 'open_'
return 'askuser'
@@ -90,7 +90,7 @@ class OpenCashBook(Wizard):
with Transaction().set_context({
'_check_access': True,
}):
- books = Book.search([])
+ books = Book.search([('btype', '!=', None)])
if len(books) > 0:
book = books[0]