diff --git a/__init__.py b/__init__.py
index b5a9987..7d33883 100644
--- a/__init__.py
+++ b/__init__.py
@@ -5,13 +5,13 @@
from trytond.pool import Pool
from .book import Book
-from .account_type import AccountType
+from .types import Type
from .line import Line, LineContext
from .wizard_openline import OpenCashBook, OpenCashBookStart
def register():
Pool.register(
- AccountType,
+ Type,
Book,
LineContext,
Line,
diff --git a/book.py b/book.py
index 60a635c..c80e7e8 100644
--- a/book.py
+++ b/book.py
@@ -3,22 +3,126 @@
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
-from trytond.model import ModelView, ModelSQL, fields
+from trytond.model import Workflow, ModelView, ModelSQL, fields, Check
+from trytond.pyson import Eval
+from trytond.exceptions import UserError
+from trytond.i18n import gettext
-class Book(ModelSQL, ModelView):
- 'Account'
+STATES = {
+ 'readonly': Eval('state', '') != 'open',
+ }
+DEPENDS=['state']
+
+sel_state_book = [
+ ('open', 'Open'),
+ ('closed', 'Closed'),
+ ('archive', 'Archive'),
+ ]
+
+
+class Book(Workflow, ModelSQL, ModelView):
+ 'Cashbook'
__name__ = 'cashbook.book'
- name = fields.Char(string='Name', required=True)
- btype = fields.Many2One(string='Account Type', required=True,
- model_name='cashbook.type', ondelete='RESTRICT')
- lines = fields.One2Many(string='Lines', field='account',
- model_name='cashbook.line')
+ name = fields.Char(string='Name', required=True,
+ states=STATES, depends=DEPENDS)
+ btype = fields.Many2One(string='Type', required=True,
+ model_name='cashbook.type', ondelete='RESTRICT',
+ states=STATES, depends=DEPENDS)
+ lines = fields.One2Many(string='Lines', field='cashbook',
+ model_name='cashbook.line',
+ states=STATES, depends=DEPENDS)
+ state = fields.Selection(string='State', required=True,
+ readonly=True, selection=sel_state_book)
+ state_string = state.translated('state')
@classmethod
def __setup__(cls):
super(Book, cls).__setup__()
cls._order.insert(0, ('name', 'ASC'))
+ t = cls.__table__()
+ cls._sql_constraints.extend([
+ ('state_val',
+ Check(t, t.state.in_(['open', 'closed', 'archive'])),
+ 'cashbook.msg_book_wrong_state_value'),
+ ])
+ cls._transitions |= set((
+ ('open', 'closed'),
+ ('closed', 'open'),
+ ('closed', 'archive'),
+ ))
+ cls._buttons.update({
+ 'wfopen': {
+ 'invisible': Eval('state', '') != 'closed',
+ 'depends': ['state'],
+ },
+ 'wfclosed': {
+ 'invisible': Eval('state') != 'open',
+ 'depends': ['state'],
+ },
+ 'wfarchive': {
+ 'invisible': Eval('state') != 'closed',
+ 'depends': ['state'],
+ },
+ })
+
+ @classmethod
+ def default_state(cls):
+ return 'open'
+
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('open')
+ def wfopen(cls, books):
+ """ open cashbook
+ """
+ pass
+
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('closed')
+ def wfclosed(cls, books):
+ """ cashbook is closed
+ """
+ pass
+
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('archive')
+ def wfarchive(cls, books):
+ """ cashbook is archived
+ """
+ pass
+
+ @classmethod
+ def write(cls, *args):
+ """ deny update if book is not 'open'
+ """
+ actions = iter(args)
+ for books, values in zip(actions, actions):
+ for book in books:
+ if book.state != 'open':
+ # allow state-update, if its the only action
+ if not (('state' in values.keys()) and (len(values.keys()) == 1)):
+ raise UserError(gettext(
+ 'cashbook.msg_book_deny_write',
+ bookname = book.rec_name,
+ state_txt = book.state_string,
+ ))
+ super(Book, cls).write(*args)
+
+ @classmethod
+ def delete(cls, books):
+ """ deny delete if book has lines
+ """
+ for book in books:
+ if (len(book.lines) > 0) and (book.state != 'archive'):
+ raise UserError(gettext(
+ 'cashbook.msg_book_deny_delete',
+ bookname = book.rec_name,
+ booklines = len(book.lines),
+ ))
+ return super(Book, cls).delete(books)
# end Book
diff --git a/book.xml b/book.xml
index e77648b..72b73ca 100644
--- a/book.xml
+++ b/book.xml
@@ -21,7 +21,7 @@ full copyright notices and license terms. -->
- Account
+ Cashbook
cashbook.book
@@ -63,5 +63,41 @@ full copyright notices and license terms. -->
+
+
+ wfopen
+ Open
+
+
+
+
+
+
+
+
+
+ wfclosed
+ Close
+
+
+
+
+
+
+
+
+
+ wfarchive
+ Archive
+
+
+
+
+
+
+
diff --git a/line.py b/line.py
index 2a26727..3d5d71d 100644
--- a/line.py
+++ b/line.py
@@ -3,10 +3,14 @@
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
-from trytond.model import ModelView, ModelSQL, Workflow, fields
+from trytond.model import ModelView, ModelSQL, Workflow, fields, Check
from trytond.pool import Pool
-from trytond.pyson import Eval, If
+from trytond.pyson import Eval, If, Or
from trytond.transaction import Transaction
+from trytond.report import Report
+from trytond.exceptions import UserError
+from trytond.i18n import gettext
+from .book import sel_state_book
sel_linetype = [
('edit', 'Edit'),
@@ -16,20 +20,23 @@ sel_linetype = [
STATES = {
- 'readonly': Eval('state', '') != 'edit',
+ 'readonly': Or(
+ Eval('state', '') != 'edit',
+ Eval('state_cashbook', '') != 'open',
+ ),
}
-DEPENDS=['state']
+DEPENDS=['state', 'state_cashbook']
class LineContext(ModelView):
'Line Context'
__name__ = 'cashbook.line.context'
- account = fields.Many2One(string='Account', required=True,
+ cashbook = fields.Many2One(string='Cashbook', required=True,
model_name='cashbook.book',
states={
- 'readonly': Eval('num_account', 0) < 2,
- }, depends=['num_account'])
+ 'readonly': Eval('num_cashbook', 0) < 2,
+ }, depends=['num_cashbook'])
date_from = fields.Date(string='Start Date', depends=['date_to'],
domain=[
If(Eval('date_to') & Eval('date_from'),
@@ -46,16 +53,16 @@ class LineContext(ModelView):
help='Show account lines in Checked-state.')
done = fields.Boolean(string='Done',
help='Show account lines in Done-state.')
- num_account = fields.Function(fields.Integer(string='Number of Accounts',
+ num_cashbook = fields.Function(fields.Integer(string='Number of Cashbook',
readonly=True, states={'invisible': True}),
- 'on_change_with_num_account')
+ 'on_change_with_num_cashbook')
@classmethod
- def default_account(cls):
+ def default_cashbook(cls):
""" get default from context
"""
context = Transaction().context
- return context.get('account', None)
+ return context.get('cashbook', None)
@classmethod
def default_date_from(cls):
@@ -85,8 +92,8 @@ class LineContext(ModelView):
context = Transaction().context
return context.get('done', False)
- def on_change_with_num_account(self, name=None):
- """ get number of accessible accounts,
+ def on_change_with_num_cashbook(self, name=None):
+ """ get number of accessible cashbooks,
depends on user-permissions
"""
CashBook = Pool().get('cashbook.book')
@@ -96,10 +103,10 @@ class LineContext(ModelView):
class Line(Workflow, ModelSQL, ModelView):
- 'Account Line'
+ 'Cashbook Line'
__name__ = 'cashbook.line'
- account = fields.Many2One(string='Account', required=True, select=True,
+ cashbook = fields.Many2One(string='Cashbook', required=True, select=True,
model_name='cashbook.book', ondelete='CASCADE', readonly=True)
date = fields.Date(string='Date', required=True, select=True,
states=STATES, depends=DEPENDS)
@@ -107,11 +114,21 @@ class Line(Workflow, ModelSQL, ModelView):
states=STATES, depends=DEPENDS)
state = fields.Selection(string='State', required=True, readonly=True,
select=True, selection=sel_linetype)
+ state_string = state.translated('state')
+ state_cashbook = fields.Function(fields.Selection(string='State of Cashbook',
+ readonly=True, states={'invisible': True}, selection=sel_state_book),
+ 'on_change_with_state_cashbook', searcher='search_state_cashbook')
@classmethod
def __setup__(cls):
super(Line, cls).__setup__()
cls._order.insert(0, ('date', 'ASC'))
+ t = cls.__table__()
+ cls._sql_constraints.extend([
+ ('state_val',
+ Check(t, t.state.in_(['edit', 'check', 'done'])),
+ 'cashbook.msg_line_wrong_state_value'),
+ ])
cls._transitions |= set((
('edit', 'check'),
('check', 'done'),
@@ -170,10 +187,58 @@ class Line(Workflow, ModelSQL, ModelView):
return IrDate.today()
@classmethod
- def default_account(cls):
+ def default_cashbook(cls):
""" get default from context
"""
context = Transaction().context
- return context.get('account', None)
+ return context.get('cashbook', None)
+
+ def get_rec_name(self, name):
+ """ short + name
+ """
+ return '%(date)s %(desc)s' % {
+ 'date': Report.format_date(self.date),
+ 'desc': (self.description or '-')[:40],
+ }
+
+ @classmethod
+ def search_rec_name(cls, name, clause):
+ """ search in description +...
+ """
+ return [('description',) + tuple(clause[1:])]
+
+ @fields.depends('cashbook', '_parent_cashbook.state')
+ def on_change_with_state_cashbook(self, name=None):
+ """ get state of cashbook
+ """
+ if self.cashbook:
+ return self.cashbook.state
+
+ @classmethod
+ def search_state_cashbook(cls, names, clause):
+ """ search in state of cashbook
+ """
+ return [('cashbook.state',) + tuple(clause[1:])]
+
+ @classmethod
+ def delete(cls, lines):
+ """ deny delete if book is not 'open' or wf is not 'edit'
+ """
+ for line in lines:
+ if line.cashbook.state == 'closed':
+ raise UserError(gettext(
+ 'cashbook.msg_line_deny_delete1',
+ linetxt = line.rec_name,
+ bookname = line.cashbook.rec_name,
+ bookstate = line.cashbook.state_string,
+ ))
+ if line.state != 'edit':
+ raise UserError(gettext(
+ 'cashbook.msg_line_deny_delete2',
+ linetxt = line.rec_name,
+ linestate = line.state_string,
+ ))
+
+ return super(Line, cls).delete(lines)
# end Line
diff --git a/line.xml b/line.xml
index 123d782..b8eed11 100644
--- a/line.xml
+++ b/line.xml
@@ -27,12 +27,12 @@ full copyright notices and license terms. -->
- Account Line
+ Cashbook Line
cashbook.line
cashbook.line.context
-
-