diff --git a/category.py b/category.py
index 674c7a2..c4d9ac8 100644
--- a/category.py
+++ b/category.py
@@ -6,6 +6,14 @@
from trytond.model import ModelView, ModelSQL, fields, Unique, tree, sequence_ordered
from trytond.transaction import Transaction
from trytond.pool import Pool
+from trytond.exceptions import UserError
+from trytond.i18n import gettext
+
+
+sel_categorytype = [
+ ('in', 'Revenue'),
+ ('out', 'Expense'),
+ ]
class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
@@ -14,6 +22,9 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
name = fields.Char(string='Name', required=True, translate=True)
description = fields.Char(string='Description', translate=True)
+ cattype = fields.Selection(string='Type', required=True,
+ help='Type of Category', selection=sel_categorytype)
+
account = fields.Many2One(string='Account', select=True,
model_name='account.account', ondelete='RESTRICT')
account_code = fields.Function(fields.Char(string='Account', readonly=True),
@@ -40,6 +51,10 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
('account_uniq', Unique(t, t.account, t.company), 'cashbook.msg_category_account_unique'),
])
+ @classmethod
+ def default_cattype(cls):
+ return 'out'
+
@staticmethod
def default_company():
return Transaction().context.get('company') or None
@@ -96,4 +111,34 @@ class Category(tree(separator='/'), sequence_ordered(), ModelSQL, ModelView):
"""
return [('account.code',) + tuple(clause[1:])]
+ @classmethod
+ def write(cls, *args):
+ """ parent.cattape == cattype,
+ update sub-categories
+ """
+ to_write = []
+ actions = iter(args)
+ for categories, values in zip(actions, actions):
+ if 'cattype' in values.keys():
+ for category in categories:
+ if category.parent:
+ if category.parent.cattype != values['cattype']:
+ raise UserError(gettext(
+ 'cashbook.msg_category_type_not_like_parent',
+ parentname = category.parent.rec_name,
+ catname = category.rec_name,
+ ))
+ cats = Category.search([('parent', 'child_of', [x.id for x in categories])])
+ if len(cats) > 0:
+ to_write.extend([
+ cats,
+ {
+ 'cattype': values['cattype'],
+ }])
+
+ super(Category, cls).write(*args)
+ if len(to_write) > 0:
+ print('\n## to_write:',to_write)
+ Category.write(*to_write)
+
# end Category
diff --git a/line.py b/line.py
index 9e6ab0e..40d6f6f 100644
--- a/line.py
+++ b/line.py
@@ -53,7 +53,13 @@ class Line(Workflow, ModelSQL, ModelView):
states=STATES, depends=DEPENDS)
category = fields.Many2One(string='Category', required=True,
model_name='cashbook.category', ondelete='RESTRICT',
- states=STATES, depends=DEPENDS)
+ states=STATES, depends=DEPENDS+['bookingtype'],
+ domain=[
+ If(
+ Eval('bookingtype', '').in_(['in', 'mvin']),
+ ('cattype', '=', 'in'),
+ ('cattype', '=', 'out'),
+ )])
category_view = fields.Function(fields.Char(string='Category', readonly=True),
'on_change_with_category_view', searcher='search_category_view')
@@ -135,6 +141,20 @@ class Line(Workflow, ModelSQL, ModelView):
"""
pass
+ @fields.depends('bookingtype', 'category')
+ def on_change_bookingtype(self):
+ """ clear category if not valid type
+ """
+ types = {
+ 'in': ['in', 'mvin'],
+ 'out': ['out', 'mvout'],
+ }
+
+ if self.bookingtype:
+ if self.category:
+ if not self.bookingtype in types.get(self.category.cattype, ''):
+ self.category = None
+
@classmethod
def default_state(cls):
""" default: edit
diff --git a/locale/de.po b/locale/de.po
index 5f65023..1114c50 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -50,6 +50,10 @@ msgctxt "model:ir.message,text:msg_category_account_unique"
msgid "The account is already in use for a category."
msgstr "Das Konto wird bereits für eine Kategorie verwendet."
+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."
+
#############
# res.group #
@@ -458,6 +462,22 @@ msgctxt "field:cashbook.category,right:"
msgid "Right"
msgstr "Rechts"
+msgctxt "field:cashbook.category,cattype:"
+msgid "Type"
+msgstr "Typ"
+
+msgctxt "help:cashbook.category,cattype:"
+msgid "Type of Category"
+msgstr "Typ der Kategorie"
+
+msgctxt "selection:cashbook.category,cattype:"
+msgid "Revenue"
+msgstr "Einnahme"
+
+msgctxt "selection:cashbook.category,cattype:"
+msgid "Expense"
+msgstr "Ausgabe"
+
#############################
# cashbook.open_lines.start #
diff --git a/message.xml b/message.xml
index ffc9d3f..9daa5b0 100644
--- a/message.xml
+++ b/message.xml
@@ -38,6 +38,9 @@ full copyright notices and license terms. -->
The account is already in use for a category.
+
+ The type of the current category '%(catname)s' must be equal to the type of the parent category '%(parentname)s'.
+
diff --git a/view/category_form.xml b/view/category_form.xml
index cf733f1..baa4999 100644
--- a/view/category_form.xml
+++ b/view/category_form.xml
@@ -8,6 +8,10 @@ full copyright notices and license terms. -->
+
+
+
+
diff --git a/view/category_list.xml b/view/category_list.xml
index f4facd4..8d9071a 100644
--- a/view/category_list.xml
+++ b/view/category_list.xml
@@ -4,6 +4,7 @@ The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
+
diff --git a/view/category_tree.xml b/view/category_tree.xml
index 1e530fc..89e5f0b 100644
--- a/view/category_tree.xml
+++ b/view/category_tree.xml
@@ -4,6 +4,7 @@ The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. -->
+