splitbuchungen + test
This commit is contained in:
parent
bdbc9dc27f
commit
aefb5cde51
9 changed files with 618 additions and 124 deletions
318
line.py
318
line.py
|
@ -81,8 +81,15 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
bookingtype = fields.Selection(string='Type', required=True,
|
bookingtype = fields.Selection(string='Type', required=True,
|
||||||
help='Type of Booking', selection=sel_bookingtype,
|
help='Type of Booking', selection=sel_bookingtype,
|
||||||
states=STATES, depends=DEPENDS)
|
states=STATES, depends=DEPENDS)
|
||||||
|
bookingtype_string = bookingtype.translated('bookingtype')
|
||||||
amount = fields.Numeric(string='Amount', digits=(16, Eval('currency_digits', 2)),
|
amount = fields.Numeric(string='Amount', digits=(16, Eval('currency_digits', 2)),
|
||||||
required=True, states=STATES, depends=DEPENDS+['currency_digits'])
|
required=True,
|
||||||
|
states={
|
||||||
|
'readonly': Or(
|
||||||
|
STATES['readonly'],
|
||||||
|
Eval('bookingtype', '').in_(['spin', 'spout']),
|
||||||
|
),
|
||||||
|
}, depends=DEPENDS+['currency_digits', 'bookingtype'])
|
||||||
debit = fields.Numeric(string='Debit', digits=(16, Eval('currency_digits', 2)),
|
debit = fields.Numeric(string='Debit', digits=(16, Eval('currency_digits', 2)),
|
||||||
required=True, readonly=True, depends=['currency_digits'])
|
required=True, readonly=True, depends=['currency_digits'])
|
||||||
credit = fields.Numeric(string='Credit', digits=(16, Eval('currency_digits', 2)),
|
credit = fields.Numeric(string='Credit', digits=(16, Eval('currency_digits', 2)),
|
||||||
|
@ -123,10 +130,15 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
}, field='reference', readonly=True)
|
}, field='reference', readonly=True)
|
||||||
splitlines = fields.One2Many(string='Split booking lines',
|
splitlines = fields.One2Many(string='Split booking lines',
|
||||||
model_name='cashbook.split',
|
model_name='cashbook.split',
|
||||||
help='The rows are created and managed by the current record.',
|
help='Rows with different categories form the total sum of the booking',
|
||||||
states={
|
states={
|
||||||
'invisible': ~Bool(Eval('splitlines')),
|
'invisible': ~Eval('bookingtype' '').in_(['spin', 'spout']),
|
||||||
}, field='line', readonly=True)
|
'readonly': Or(
|
||||||
|
~Eval('bookingtype' '').in_(['spin', 'spout']),
|
||||||
|
STATES['readonly'],
|
||||||
|
),
|
||||||
|
'required': Eval('bookingtype' '').in_(['spin', 'spout']),
|
||||||
|
}, field='line', depends=DEPENDS+['bookingtype'])
|
||||||
|
|
||||||
reconciliation = fields.Many2One(string='Reconciliation', readonly=True,
|
reconciliation = fields.Many2One(string='Reconciliation', readonly=True,
|
||||||
model_name='cashbook.recon', ondelete='SET NULL',
|
model_name='cashbook.recon', ondelete='SET NULL',
|
||||||
|
@ -143,9 +155,9 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
'on_change_with_balance')
|
'on_change_with_balance')
|
||||||
|
|
||||||
currency = fields.Function(fields.Many2One(model_name='currency.currency',
|
currency = fields.Function(fields.Many2One(model_name='currency.currency',
|
||||||
string="Currency"), 'on_change_with_currency')
|
string="Currency", readonly=True), 'on_change_with_currency')
|
||||||
currency_digits = fields.Function(fields.Integer(string='Currency Digits'),
|
currency_digits = fields.Function(fields.Integer(string='Currency Digits',
|
||||||
'on_change_with_currency_digits')
|
readonly=True), 'on_change_with_currency_digits')
|
||||||
|
|
||||||
state = fields.Selection(string='State', required=True, readonly=True,
|
state = fields.Selection(string='State', required=True, readonly=True,
|
||||||
select=True, selection=sel_linetype)
|
select=True, selection=sel_linetype)
|
||||||
|
@ -351,14 +363,14 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
'type': gettext('cashbook.msg_line_bookingtype_%s' % self.bookingtype),
|
'type': gettext('cashbook.msg_line_bookingtype_%s' % self.bookingtype),
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_amount_by_second_currency(self, to_currency):
|
def get_amount_by_second_currency(self, to_currency, amount=None):
|
||||||
""" get amount, calculate credit/debit from currency of current
|
""" get amount, calculate credit/debit from currency of current
|
||||||
cashbook to 'to_currency'
|
cashbook to 'to_currency'
|
||||||
"""
|
"""
|
||||||
Currency = Pool().get('currency.currency')
|
Currency = Pool().get('currency.currency')
|
||||||
|
|
||||||
values = {
|
values = {
|
||||||
'amount': self.amount,
|
'amount': amount if amount is not None else self.amount,
|
||||||
}
|
}
|
||||||
|
|
||||||
if to_currency.id != self.cashbook.currency.id:
|
if to_currency.id != self.cashbook.currency.id:
|
||||||
|
@ -402,18 +414,6 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
|
|
||||||
return [tab2]
|
return [tab2]
|
||||||
|
|
||||||
@fields.depends('party', 'booktransf', 'bookingtype')
|
|
||||||
def on_change_with_payee(self, name=None):
|
|
||||||
""" get party or cashbook
|
|
||||||
"""
|
|
||||||
if self.bookingtype:
|
|
||||||
if self.bookingtype in ['in', 'out', 'spin', 'spout']:
|
|
||||||
if self.party:
|
|
||||||
return 'party.party,%d' % self.party.id
|
|
||||||
elif self.bookingtype in ['mvin', 'mvout']:
|
|
||||||
if self.booktransf:
|
|
||||||
return 'cashbook.book,%d' % self.booktransf.id
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search_payee(cls, names, clause):
|
def search_payee(cls, names, clause):
|
||||||
""" search in payee for party or cashbook
|
""" search in payee for party or cashbook
|
||||||
|
@ -423,36 +423,12 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
('booktransf.rec_name',) + tuple(clause[1:]),
|
('booktransf.rec_name',) + tuple(clause[1:]),
|
||||||
]
|
]
|
||||||
|
|
||||||
@fields.depends('category')
|
|
||||||
def on_change_with_category_view(self, name=None):
|
|
||||||
""" show optimizef form of category for list-view
|
|
||||||
"""
|
|
||||||
Configuration = Pool().get('cashbook.configuration')
|
|
||||||
|
|
||||||
if self.category:
|
|
||||||
cfg1 = Configuration.get_singleton()
|
|
||||||
|
|
||||||
if getattr(cfg1, 'catnamelong', True) == True:
|
|
||||||
return self.category.rec_name
|
|
||||||
else :
|
|
||||||
return self.category.name
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search_category_view(cls, name, clause):
|
def search_category_view(cls, name, clause):
|
||||||
""" search in category
|
""" search in category
|
||||||
"""
|
"""
|
||||||
return [('category.rec_name',) + tuple(clause[1:])]
|
return [('category.rec_name',) + tuple(clause[1:])]
|
||||||
|
|
||||||
@fields.depends('date')
|
|
||||||
def on_change_with_month(self, name=None):
|
|
||||||
""" get difference of month to current date
|
|
||||||
"""
|
|
||||||
IrDate = Pool().get('ir.date')
|
|
||||||
if self.date is not None:
|
|
||||||
dt1 = IrDate.today()
|
|
||||||
return (12 * dt1.year + dt1.month) - \
|
|
||||||
(12 * self.date.year + self.date.month)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search_month(cls, names, clause):
|
def search_month(cls, names, clause):
|
||||||
""" search in month
|
""" search in month
|
||||||
|
@ -472,6 +448,75 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
)
|
)
|
||||||
return [('id', 'in', query)]
|
return [('id', 'in', query)]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def search_state_cashbook(cls, names, clause):
|
||||||
|
""" search in state of cashbook
|
||||||
|
"""
|
||||||
|
return [('cashbook.state',) + tuple(clause[1:])]
|
||||||
|
|
||||||
|
@fields.depends('amount', 'splitlines')
|
||||||
|
def on_change_splitlines(self):
|
||||||
|
""" update amount if splitlines change
|
||||||
|
"""
|
||||||
|
self.amount = sum([x.amount for x in self.splitlines if x.amount is not None])
|
||||||
|
|
||||||
|
@fields.depends('bookingtype', 'category', 'splitlines')
|
||||||
|
def on_change_bookingtype(self):
|
||||||
|
""" clear category if not valid type
|
||||||
|
"""
|
||||||
|
types = {
|
||||||
|
'in': ['in', 'mvin', 'spin'],
|
||||||
|
'out': ['out', 'mvout', 'spout'],
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.bookingtype:
|
||||||
|
if self.category:
|
||||||
|
if not self.bookingtype in types.get(self.category.cattype, ''):
|
||||||
|
self.category = None
|
||||||
|
|
||||||
|
if self.bookingtype in ['spin', 'spout']:
|
||||||
|
for spline in self.splitlines:
|
||||||
|
if not self.bookingtype in types.get(getattr(spline.category, 'cattype', '-'), ''):
|
||||||
|
spline.category = None
|
||||||
|
else :
|
||||||
|
self.splitlines = []
|
||||||
|
|
||||||
|
@fields.depends('party', 'booktransf', 'bookingtype')
|
||||||
|
def on_change_with_payee(self, name=None):
|
||||||
|
""" get party or cashbook
|
||||||
|
"""
|
||||||
|
if self.bookingtype:
|
||||||
|
if self.bookingtype in ['in', 'out', 'spin', 'spout']:
|
||||||
|
if self.party:
|
||||||
|
return 'party.party,%d' % self.party.id
|
||||||
|
elif self.bookingtype in ['mvin', 'mvout']:
|
||||||
|
if self.booktransf:
|
||||||
|
return 'cashbook.book,%d' % self.booktransf.id
|
||||||
|
|
||||||
|
@fields.depends('category')
|
||||||
|
def on_change_with_category_view(self, name=None):
|
||||||
|
""" show optimizef form of category for list-view
|
||||||
|
"""
|
||||||
|
Configuration = Pool().get('cashbook.configuration')
|
||||||
|
|
||||||
|
if self.category:
|
||||||
|
cfg1 = Configuration.get_singleton()
|
||||||
|
|
||||||
|
if getattr(cfg1, 'catnamelong', True) == True:
|
||||||
|
return self.category.rec_name
|
||||||
|
else :
|
||||||
|
return self.category.name
|
||||||
|
|
||||||
|
@fields.depends('date')
|
||||||
|
def on_change_with_month(self, name=None):
|
||||||
|
""" get difference of month to current date
|
||||||
|
"""
|
||||||
|
IrDate = Pool().get('ir.date')
|
||||||
|
if self.date is not None:
|
||||||
|
dt1 = IrDate.today()
|
||||||
|
return (12 * dt1.year + dt1.month) - \
|
||||||
|
(12 * self.date.year + self.date.month)
|
||||||
|
|
||||||
@fields.depends('cashbook', '_parent_cashbook.owner')
|
@fields.depends('cashbook', '_parent_cashbook.owner')
|
||||||
def on_change_with_owner_cashbook(self, name=None):
|
def on_change_with_owner_cashbook(self, name=None):
|
||||||
""" get current owner
|
""" get current owner
|
||||||
|
@ -486,26 +531,6 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
if self.cashbook:
|
if self.cashbook:
|
||||||
return self.cashbook.state
|
return self.cashbook.state
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def search_state_cashbook(cls, names, clause):
|
|
||||||
""" search in state of cashbook
|
|
||||||
"""
|
|
||||||
return [('cashbook.state',) + tuple(clause[1:])]
|
|
||||||
|
|
||||||
@fields.depends('bookingtype', 'category')
|
|
||||||
def on_change_bookingtype(self):
|
|
||||||
""" clear category if not valid type
|
|
||||||
"""
|
|
||||||
types = {
|
|
||||||
'in': ['in', 'mvin', 'spin'],
|
|
||||||
'out': ['out', 'mvout', 'spout'],
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.bookingtype:
|
|
||||||
if self.category:
|
|
||||||
if not self.bookingtype in types.get(self.category.cattype, ''):
|
|
||||||
self.category = None
|
|
||||||
|
|
||||||
@fields.depends('cashbook', '_parent_cashbook.currency')
|
@fields.depends('cashbook', '_parent_cashbook.currency')
|
||||||
def on_change_with_currency(self, name=None):
|
def on_change_with_currency(self, name=None):
|
||||||
""" currency of cashbook
|
""" currency of cashbook
|
||||||
|
@ -566,6 +591,31 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
break
|
break
|
||||||
return balance
|
return balance
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_by_bookingtype(cls, values, line=None):
|
||||||
|
""" clear some fields by value of bookingtype
|
||||||
|
"""
|
||||||
|
values2 = {}
|
||||||
|
values2.update(values)
|
||||||
|
|
||||||
|
bookingtype = values2.get('bookingtype', getattr(line, 'bookingtype', None))
|
||||||
|
if (bookingtype in ['in', 'out', 'mvin', 'mvout']) and \
|
||||||
|
('splitlines' not in values2.keys()):
|
||||||
|
if line:
|
||||||
|
if len(line.splitlines) > 0:
|
||||||
|
values2['splitlines'] = [('delete', [x.id for x in line.splitlines])]
|
||||||
|
|
||||||
|
if bookingtype in ['in', 'out']:
|
||||||
|
values2['booktransf'] = None
|
||||||
|
|
||||||
|
if bookingtype in ['spin', 'spout']:
|
||||||
|
values2['category'] = None
|
||||||
|
values2['booktransf'] = None
|
||||||
|
|
||||||
|
if bookingtype in ['mvin', 'mvout']:
|
||||||
|
values2['category'] = None
|
||||||
|
return values2
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_debit_credit(cls, values):
|
def get_debit_credit(cls, values):
|
||||||
""" compute debit/credit from amount
|
""" compute debit/credit from amount
|
||||||
|
@ -593,11 +643,33 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
raise ValueError('invalid "bookingtype"')
|
raise ValueError('invalid "bookingtype"')
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_amount_by_splitlines(cls, lines):
|
||||||
|
""" update amounts from split-lines
|
||||||
|
"""
|
||||||
|
Line2 = Pool().get('cashbook.line')
|
||||||
|
|
||||||
|
to_write = []
|
||||||
|
for line in lines:
|
||||||
|
to_write.extend([
|
||||||
|
[line],
|
||||||
|
{
|
||||||
|
'amount': sum([x.amount for x in line.splitlines]),
|
||||||
|
}])
|
||||||
|
if len(to_write) > 0:
|
||||||
|
Line2.write(*to_write)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate(cls, lines):
|
def validate(cls, lines):
|
||||||
""" deny date before 'start_date' of cashbook
|
""" deny date before 'start_date' of cashbook
|
||||||
"""
|
"""
|
||||||
super(Line, cls).validate(lines)
|
super(Line, cls).validate(lines)
|
||||||
|
|
||||||
|
types = {
|
||||||
|
'in': ['in', 'mvin', 'spin'],
|
||||||
|
'out': ['out', 'mvout', 'spout'],
|
||||||
|
}
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.date < line.cashbook.start_date:
|
if line.date < line.cashbook.start_date:
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
|
@ -606,6 +678,77 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
recname = line.rec_name,
|
recname = line.rec_name,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# line: category <--> bookingtype?
|
||||||
|
if line.category:
|
||||||
|
if not line.bookingtype in types[line.category.cattype]:
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_line_invalid_category',
|
||||||
|
recname = line.rec_name,
|
||||||
|
booktype = line.bookingtype_string,
|
||||||
|
))
|
||||||
|
|
||||||
|
# splitline: category <--> bookingtype?
|
||||||
|
for spline in line.splitlines:
|
||||||
|
if not line.bookingtype in types[spline.category.cattype]:
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_line_split_invalid_category',
|
||||||
|
recname = line.rec_name,
|
||||||
|
splitrecname = spline.rec_name,
|
||||||
|
booktype = line.bookingtype_string,
|
||||||
|
))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_permission_write(cls, lines, values={}):
|
||||||
|
""" deny update if cashbook.line!='open',
|
||||||
|
"""
|
||||||
|
for line in lines:
|
||||||
|
# deny write if cashbook is not open
|
||||||
|
if line.cashbook.state != 'open':
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_book_deny_write',
|
||||||
|
bookname = line.cashbook.rec_name,
|
||||||
|
state_txt = line.cashbook.state_string,
|
||||||
|
))
|
||||||
|
|
||||||
|
# deny write if reconciliation is 'check' or 'done'
|
||||||
|
if line.reconciliation:
|
||||||
|
if line.reconciliation.state == 'done':
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_line_deny_write_by_reconciliation',
|
||||||
|
recname = line.rec_name,
|
||||||
|
reconame = line.reconciliation.rec_name,
|
||||||
|
))
|
||||||
|
|
||||||
|
# deny write if line is not 'Edit'
|
||||||
|
if line.state != 'edit':
|
||||||
|
# allow state-update, if its the only action
|
||||||
|
if not ((len(set({'state', 'reconciliation'}).intersection(values.keys())) > 0) \
|
||||||
|
and (len(values.keys()) == 1)):
|
||||||
|
raise UserError(gettext(
|
||||||
|
'cashbook.msg_line_deny_write',
|
||||||
|
recname = line.rec_name,
|
||||||
|
state_txt = line.state_string,
|
||||||
|
))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_permission_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,
|
||||||
|
))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def copy(cls, lines, default=None):
|
def copy(cls, lines, default=None):
|
||||||
""" reset values
|
""" reset values
|
||||||
|
@ -625,6 +768,7 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
vlist = [x.copy() for x in vlist]
|
vlist = [x.copy() for x in vlist]
|
||||||
for values in vlist:
|
for values in vlist:
|
||||||
values.update(cls.get_debit_credit(values))
|
values.update(cls.get_debit_credit(values))
|
||||||
|
values.update(cls.clear_by_bookingtype(values))
|
||||||
|
|
||||||
# deny add to reconciliation if state is not 'check' or 'done'
|
# deny add to reconciliation if state is not 'check' or 'done'
|
||||||
if values.get('reconciliation', None):
|
if values.get('reconciliation', None):
|
||||||
|
@ -650,14 +794,9 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
actions = iter(args)
|
actions = iter(args)
|
||||||
to_write = []
|
to_write = []
|
||||||
for lines, values in zip(actions, actions):
|
for lines, values in zip(actions, actions):
|
||||||
|
cls.check_permission_write(lines, values)
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
# deny write if cashbook is not open
|
|
||||||
if line.cashbook.state != 'open':
|
|
||||||
raise UserError(gettext(
|
|
||||||
'cashbook.msg_book_deny_write',
|
|
||||||
bookname = line.cashbook.rec_name,
|
|
||||||
state_txt = line.cashbook.state_string,
|
|
||||||
))
|
|
||||||
if line.reconciliation:
|
if line.reconciliation:
|
||||||
# deny state-change to 'edit' if line is linked to reconciliation
|
# deny state-change to 'edit' if line is linked to reconciliation
|
||||||
if values.get('state', '-') == 'edit':
|
if values.get('state', '-') == 'edit':
|
||||||
|
@ -666,24 +805,6 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
recname = line.rec_name,
|
recname = line.rec_name,
|
||||||
))
|
))
|
||||||
|
|
||||||
# deny write if reconciliation is 'check' or 'done'
|
|
||||||
if line.reconciliation.state == 'done':
|
|
||||||
raise UserError(gettext(
|
|
||||||
'cashbook.msg_line_deny_write_by_reconciliation',
|
|
||||||
recname = line.rec_name,
|
|
||||||
reconame = line.reconciliation.rec_name,
|
|
||||||
))
|
|
||||||
# deny write if line is not 'Edit'
|
|
||||||
if line.state != 'edit':
|
|
||||||
# allow state-update, if its the only action
|
|
||||||
if not ((len(set({'state', 'reconciliation'}).intersection(values.keys())) > 0) \
|
|
||||||
and (len(values.keys()) == 1)):
|
|
||||||
raise UserError(gettext(
|
|
||||||
'cashbook.msg_line_deny_write',
|
|
||||||
recname = line.rec_name,
|
|
||||||
state_txt = line.state_string,
|
|
||||||
))
|
|
||||||
|
|
||||||
# deny add to reconciliation if state is not 'check' or 'done'
|
# deny add to reconciliation if state is not 'check' or 'done'
|
||||||
if values.get('reconciliation', None):
|
if values.get('reconciliation', None):
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
@ -698,6 +819,7 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
for line in lines:
|
for line in lines:
|
||||||
values2 = {}
|
values2 = {}
|
||||||
values2.update(values)
|
values2.update(values)
|
||||||
|
values2.update(cls.clear_by_bookingtype(values, line))
|
||||||
values2.update(cls.get_debit_credit({
|
values2.update(cls.get_debit_credit({
|
||||||
x:values.get(x, getattr(line, x)) for x in ['amount', 'bookingtype']
|
x:values.get(x, getattr(line, x)) for x in ['amount', 'bookingtype']
|
||||||
}))
|
}))
|
||||||
|
@ -710,21 +832,7 @@ class Line(Workflow, ModelSQL, ModelView):
|
||||||
def delete(cls, lines):
|
def delete(cls, lines):
|
||||||
""" deny delete if book is not 'open' or wf is not 'edit'
|
""" deny delete if book is not 'open' or wf is not 'edit'
|
||||||
"""
|
"""
|
||||||
for line in lines:
|
cls.check_permission_delete(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)
|
return super(Line, cls).delete(lines)
|
||||||
|
|
||||||
# end Line
|
# end Line
|
||||||
|
|
32
locale/de.po
32
locale/de.po
|
@ -142,6 +142,14 @@ msgctxt "model:ir.message,text:msg_line_date_before_book"
|
||||||
msgid "The date of the cashbook line '%(recname)s' cannot be earlier than the start date '%(datebook)s' of the cashbook."
|
msgid "The date of the cashbook line '%(recname)s' cannot be earlier than the start date '%(datebook)s' of the cashbook."
|
||||||
msgstr "Das Datum der Kassenbuchzeile '%(recname)s' kann nicht vor dem Anfangsdatum '%(datebook)s' des Kassenbuchs liegen."
|
msgstr "Das Datum der Kassenbuchzeile '%(recname)s' kann nicht vor dem Anfangsdatum '%(datebook)s' des Kassenbuchs liegen."
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_line_split_invalid_category"
|
||||||
|
msgid "The category of the split booking line '%(splitrecname)s' does not match the posting type '%(booktype)s' of the line '%(recname)s'."
|
||||||
|
msgstr "Die Kategorie der Splitbuchungszeile '%(splitrecname)s' paßt nicht zum Buchungstyp '%(booktype)s' der Zeile '%(recname)s'."
|
||||||
|
|
||||||
|
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'."
|
||||||
|
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# res.group #
|
# res.group #
|
||||||
|
@ -482,6 +490,10 @@ msgctxt "model:cashbook.split,name:"
|
||||||
msgid "Split booking line"
|
msgid "Split booking line"
|
||||||
msgstr "Splitbuchungszeile"
|
msgstr "Splitbuchungszeile"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.split:"
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
msgctxt "field:cashbook.split,line:"
|
msgctxt "field:cashbook.split,line:"
|
||||||
msgid "Line"
|
msgid "Line"
|
||||||
msgstr "Zeile"
|
msgstr "Zeile"
|
||||||
|
@ -494,6 +506,10 @@ msgctxt "field:cashbook.split,category:"
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategorie"
|
msgstr "Kategorie"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,category_view:"
|
||||||
|
msgid "Category"
|
||||||
|
msgstr "Kategorie"
|
||||||
|
|
||||||
msgctxt "field:cashbook.split,amount:"
|
msgctxt "field:cashbook.split,amount:"
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
msgstr "Betrag"
|
msgstr "Betrag"
|
||||||
|
@ -582,6 +598,14 @@ msgctxt "view:cashbook.line:"
|
||||||
msgid "State"
|
msgid "State"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.line:"
|
||||||
|
msgid "Split booking lines"
|
||||||
|
msgstr "Splitbuchungszeilen"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.line:"
|
||||||
|
msgid "References"
|
||||||
|
msgstr "Referenzen"
|
||||||
|
|
||||||
msgctxt "field:cashbook.line,cashbook:"
|
msgctxt "field:cashbook.line,cashbook:"
|
||||||
msgid "Cashbook"
|
msgid "Cashbook"
|
||||||
msgstr "Kassenbuch"
|
msgstr "Kassenbuch"
|
||||||
|
@ -734,6 +758,14 @@ msgctxt "field:cashbook.line,number:"
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Nummer"
|
msgstr "Nummer"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.line,splitlines:"
|
||||||
|
msgid "Split booking lines"
|
||||||
|
msgstr "Splitbuchungszeilen"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.line,splitlines:"
|
||||||
|
msgid "Rows with different categories form the total sum of the booking"
|
||||||
|
msgstr "Zeilen mit unterschiedlichen Kategorien bilden die Gesamtsumme der Buchung"
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# cashbook.type #
|
# cashbook.type #
|
||||||
|
|
140
locale/en.po
140
locale/en.po
|
@ -106,10 +106,18 @@ msgctxt "model:ir.message,text:msg_line_bookingtype_in"
|
||||||
msgid "Rev"
|
msgid "Rev"
|
||||||
msgstr "Rev"
|
msgstr "Rev"
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_line_bookingtype_spin"
|
||||||
|
msgid "Rev/Sp"
|
||||||
|
msgstr "Rev/Sp"
|
||||||
|
|
||||||
msgctxt "model:ir.message,text:msg_line_bookingtype_out"
|
msgctxt "model:ir.message,text:msg_line_bookingtype_out"
|
||||||
msgid "Exp"
|
msgid "Exp"
|
||||||
msgstr "Exp"
|
msgstr "Exp"
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_line_bookingtype_spout"
|
||||||
|
msgid "Exp/Sp"
|
||||||
|
msgstr "Exp/Sp"
|
||||||
|
|
||||||
msgctxt "model:ir.message,text:msg_line_bookingtype_mvin"
|
msgctxt "model:ir.message,text:msg_line_bookingtype_mvin"
|
||||||
msgid "from"
|
msgid "from"
|
||||||
msgstr "from"
|
msgstr "from"
|
||||||
|
@ -130,6 +138,14 @@ msgctxt "model:ir.message,text:msg_line_date_before_book"
|
||||||
msgid "The date of the cashbook line '%(recname)s' cannot be earlier than the start date '%(datebook)s' of the cashbook."
|
msgid "The date of the cashbook line '%(recname)s' cannot be earlier than the start date '%(datebook)s' of the cashbook."
|
||||||
msgstr "The date of the cashbook line '%(recname)s' cannot be earlier than the start date '%(datebook)s' of the cashbook."
|
msgstr "The date of the cashbook line '%(recname)s' cannot be earlier than the start date '%(datebook)s' of the cashbook."
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_line_split_invalid_category"
|
||||||
|
msgid "The category of the split booking line '%(splitrecname)s' does not match the posting type '%(booktype)s' of the line '%(recname)s'."
|
||||||
|
msgstr "The category of the split booking line '%(splitrecname)s' does not match the posting type '%(booktype)s' of the line '%(recname)s'."
|
||||||
|
|
||||||
|
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:res.group,name:group_cashbook"
|
msgctxt "model:res.group,name:group_cashbook"
|
||||||
msgid "Cashbook"
|
msgid "Cashbook"
|
||||||
msgstr "Cashbook"
|
msgstr "Cashbook"
|
||||||
|
@ -154,6 +170,10 @@ msgctxt "model:ir.rule.group,name:rg_book_read_nonowner"
|
||||||
msgid "Observers and Reviewers: Cashbook read"
|
msgid "Observers and Reviewers: Cashbook read"
|
||||||
msgstr "Observers and Reviewers: Cashbook read"
|
msgstr "Observers and Reviewers: Cashbook read"
|
||||||
|
|
||||||
|
msgctxt "model:ir.rule.group,name:rg_split_write_adm"
|
||||||
|
msgid "Administrators: Splitbooking line read/write"
|
||||||
|
msgstr "Administrators: Splitbooking line read/write"
|
||||||
|
|
||||||
msgctxt "model:ir.rule.group,name:rg_book_write_adm"
|
msgctxt "model:ir.rule.group,name:rg_book_write_adm"
|
||||||
msgid "Administrators: Cashbook read/write"
|
msgid "Administrators: Cashbook read/write"
|
||||||
msgstr "Administrators: Cashbook read/write"
|
msgstr "Administrators: Cashbook read/write"
|
||||||
|
@ -162,10 +182,18 @@ msgctxt "model:ir.rule.group,name:rg_line_write_adm"
|
||||||
msgid "Administrators: Cashbook line read/write"
|
msgid "Administrators: Cashbook line read/write"
|
||||||
msgstr "Administrators: Cashbook line read/write"
|
msgstr "Administrators: Cashbook line read/write"
|
||||||
|
|
||||||
|
msgctxt "model:ir.rule.group,name:rg_split_write"
|
||||||
|
msgid "Owners and reviewers: Splitbooking line write"
|
||||||
|
msgstr "Owners and reviewers: Splitbooking line write"
|
||||||
|
|
||||||
msgctxt "model:ir.rule.group,name:rg_line_write"
|
msgctxt "model:ir.rule.group,name:rg_line_write"
|
||||||
msgid "Owners and reviewers: Cashbook line write"
|
msgid "Owners and reviewers: Cashbook line write"
|
||||||
msgstr "Owners and reviewers: Cashbook line write"
|
msgstr "Owners and reviewers: Cashbook line write"
|
||||||
|
|
||||||
|
msgctxt "model:ir.rule.group,name:rg_split_read"
|
||||||
|
msgid "Observer: Splitbooking line read"
|
||||||
|
msgstr "Observer: Splitbooking line read"
|
||||||
|
|
||||||
msgctxt "model:ir.rule.group,name:rg_line_read"
|
msgctxt "model:ir.rule.group,name:rg_line_read"
|
||||||
msgid "Observer: Cashbook line read"
|
msgid "Observer: Cashbook line read"
|
||||||
msgstr "Observer: Cashbook line read"
|
msgstr "Observer: Cashbook line read"
|
||||||
|
@ -174,6 +202,10 @@ msgctxt "model:ir.rule.group,name:rg_line_read"
|
||||||
msgid "User in companies"
|
msgid "User in companies"
|
||||||
msgstr "User in companies"
|
msgstr "User in companies"
|
||||||
|
|
||||||
|
msgctxt "model:ir.rule.group,name:rg_split_companies"
|
||||||
|
msgid "User in companies"
|
||||||
|
msgstr "User in companies"
|
||||||
|
|
||||||
msgctxt "model:ir.rule.group,name:rg_type_companies"
|
msgctxt "model:ir.rule.group,name:rg_type_companies"
|
||||||
msgid "User in companies"
|
msgid "User in companies"
|
||||||
msgstr "User in companies"
|
msgstr "User in companies"
|
||||||
|
@ -414,6 +446,90 @@ 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."
|
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."
|
msgstr "The numbering of the lines is done in the step Check. If the check mark is inactive, this happens with Done."
|
||||||
|
|
||||||
|
msgctxt "model:cashbook.split,name:"
|
||||||
|
msgid "Split booking line"
|
||||||
|
msgstr "Split booking line"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.split:"
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Description"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,line:"
|
||||||
|
msgid "Line"
|
||||||
|
msgstr "Line"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,description:"
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Description"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,category:"
|
||||||
|
msgid "Category"
|
||||||
|
msgstr "Category"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,category_view:"
|
||||||
|
msgid "Category"
|
||||||
|
msgstr "Category"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,amount:"
|
||||||
|
msgid "Amount"
|
||||||
|
msgstr "Amount"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,currency:"
|
||||||
|
msgid "Currency"
|
||||||
|
msgstr "Currency"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,currency_digits:"
|
||||||
|
msgid "Currency Digits"
|
||||||
|
msgstr "Currency Digits"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,bookingtype:"
|
||||||
|
msgid "Type"
|
||||||
|
msgstr "Type"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,bookingtype:"
|
||||||
|
msgid "Revenue"
|
||||||
|
msgstr "Revenue"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,bookingtype:"
|
||||||
|
msgid "Revenue Splitbooking"
|
||||||
|
msgstr "Revenue Splitbooking"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,bookingtype:"
|
||||||
|
msgid "Expense"
|
||||||
|
msgstr "Expense"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,bookingtype:"
|
||||||
|
msgid "Expense Splitbooking"
|
||||||
|
msgstr "Expense Splitbooking"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,bookingtype:"
|
||||||
|
msgid "Transfer from"
|
||||||
|
msgstr "Transfer from"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,bookingtype:"
|
||||||
|
msgid "Transfer to"
|
||||||
|
msgstr "Transfer to"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,state:"
|
||||||
|
msgid "State"
|
||||||
|
msgstr "State"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,state:"
|
||||||
|
msgid "Edit"
|
||||||
|
msgstr "Edit"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,state:"
|
||||||
|
msgid "Checked"
|
||||||
|
msgstr "Checked"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.split,state:"
|
||||||
|
msgid "Done"
|
||||||
|
msgstr "Done"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.split,state_cashbook:"
|
||||||
|
msgid "State of Cashbook"
|
||||||
|
msgstr "State of Cashbook"
|
||||||
|
|
||||||
msgctxt "model:cashbook.line,name:"
|
msgctxt "model:cashbook.line,name:"
|
||||||
msgid "Cashbook Line"
|
msgid "Cashbook Line"
|
||||||
msgstr "Cashbook Line"
|
msgstr "Cashbook Line"
|
||||||
|
@ -438,6 +554,14 @@ msgctxt "view:cashbook.line:"
|
||||||
msgid "State"
|
msgid "State"
|
||||||
msgstr "State"
|
msgstr "State"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.line:"
|
||||||
|
msgid "Split booking lines"
|
||||||
|
msgstr "Split booking lines"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.line:"
|
||||||
|
msgid "References"
|
||||||
|
msgstr "References"
|
||||||
|
|
||||||
msgctxt "field:cashbook.line,cashbook:"
|
msgctxt "field:cashbook.line,cashbook:"
|
||||||
msgid "Cashbook"
|
msgid "Cashbook"
|
||||||
msgstr "Cashbook"
|
msgstr "Cashbook"
|
||||||
|
@ -490,10 +614,18 @@ msgctxt "selection:cashbook.line,bookingtype:"
|
||||||
msgid "Revenue"
|
msgid "Revenue"
|
||||||
msgstr "Revenue"
|
msgstr "Revenue"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.line,bookingtype:"
|
||||||
|
msgid "Revenue Splitbooking"
|
||||||
|
msgstr "Revenue Splitbooking"
|
||||||
|
|
||||||
msgctxt "selection:cashbook.line,bookingtype:"
|
msgctxt "selection:cashbook.line,bookingtype:"
|
||||||
msgid "Expense"
|
msgid "Expense"
|
||||||
msgstr "Expense"
|
msgstr "Expense"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.line,bookingtype:"
|
||||||
|
msgid "Expense Splitbooking"
|
||||||
|
msgstr "Expense Splitbooking"
|
||||||
|
|
||||||
msgctxt "selection:cashbook.line,bookingtype:"
|
msgctxt "selection:cashbook.line,bookingtype:"
|
||||||
msgid "Transfer from"
|
msgid "Transfer from"
|
||||||
msgstr "Transfer from"
|
msgstr "Transfer from"
|
||||||
|
@ -582,6 +714,14 @@ msgctxt "field:cashbook.line,number:"
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Number"
|
msgstr "Number"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.line,splitlines:"
|
||||||
|
msgid "Split booking lines"
|
||||||
|
msgstr "Split booking lines"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.line,splitlines:"
|
||||||
|
msgid "Rows with different categories form the total sum of the booking"
|
||||||
|
msgstr "Rows with different categories form the total sum of the booking"
|
||||||
|
|
||||||
msgctxt "model:cashbook.type,name:"
|
msgctxt "model:cashbook.type,name:"
|
||||||
msgid "Cashbook Type"
|
msgid "Cashbook Type"
|
||||||
msgstr "Cashbook Type"
|
msgstr "Cashbook Type"
|
||||||
|
|
|
@ -107,6 +107,12 @@ full copyright notices and license terms. -->
|
||||||
<record model="ir.message" id="msg_line_date_before_book">
|
<record model="ir.message" id="msg_line_date_before_book">
|
||||||
<field name="text">The date of the cashbook line '%(recname)s' cannot be earlier than the start date '%(datebook)s' of the cashbook.</field>
|
<field name="text">The date of the cashbook line '%(recname)s' cannot be earlier than the start date '%(datebook)s' of the cashbook.</field>
|
||||||
</record>
|
</record>
|
||||||
|
<record model="ir.message" id="msg_line_split_invalid_category">
|
||||||
|
<field name="text">The category of the split booking line '%(splitrecname)s' does not match the posting type '%(booktype)s' of the line '%(recname)s'.</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.message" id="msg_line_invalid_category">
|
||||||
|
<field name="text">The category of the booking line '%(recname)s' does not match the posting type '%(booktype)s'.</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
||||||
|
|
110
splitline.py
110
splitline.py
|
@ -7,6 +7,9 @@
|
||||||
from trytond.model import ModelView, ModelSQL, Workflow, fields, Check
|
from trytond.model import ModelView, ModelSQL, Workflow, fields, Check
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.pyson import Eval, If
|
from trytond.pyson import Eval, If
|
||||||
|
from trytond.report import Report
|
||||||
|
from trytond.i18n import gettext
|
||||||
|
from trytond.transaction import Transaction
|
||||||
from .line import sel_linetype, sel_bookingtype, STATES, DEPENDS
|
from .line import sel_linetype, sel_bookingtype, STATES, DEPENDS
|
||||||
from .book import sel_state_book
|
from .book import sel_state_book
|
||||||
|
|
||||||
|
@ -22,28 +25,74 @@ class SplitLine(ModelSQL, ModelView):
|
||||||
states=STATES, depends=DEPENDS)
|
states=STATES, depends=DEPENDS)
|
||||||
category = fields.Many2One(string='Category',
|
category = fields.Many2One(string='Category',
|
||||||
model_name='cashbook.category', ondelete='RESTRICT',
|
model_name='cashbook.category', ondelete='RESTRICT',
|
||||||
states=STATES, depends=DEPENDS+['bookingtype'],
|
states=STATES, depends=DEPENDS+['bookingtype'], required=True,
|
||||||
required=True,
|
|
||||||
domain=[
|
domain=[
|
||||||
If(
|
If(
|
||||||
Eval('bookingtype', '').in_(['in', 'mvin']),
|
Eval('bookingtype', '') == 'spin',
|
||||||
('cattype', '=', 'in'),
|
('cattype', '=', 'in'),
|
||||||
('cattype', '=', 'out'),
|
('cattype', '=', 'out'),
|
||||||
)])
|
)])
|
||||||
|
category_view = fields.Function(fields.Char(string='Category', readonly=True),
|
||||||
|
'on_change_with_category_view')
|
||||||
amount = fields.Numeric(string='Amount', digits=(16, Eval('currency_digits', 2)),
|
amount = fields.Numeric(string='Amount', digits=(16, Eval('currency_digits', 2)),
|
||||||
required=True, states=STATES, depends=DEPENDS+['currency_digits'])
|
required=True, states=STATES, depends=DEPENDS+['currency_digits'])
|
||||||
|
|
||||||
currency = fields.Function(fields.Many2One(model_name='currency.currency',
|
currency = fields.Function(fields.Many2One(model_name='currency.currency',
|
||||||
string="Currency"), 'on_change_with_currency')
|
string="Currency", readonly=True), 'on_change_with_currency')
|
||||||
currency_digits = fields.Function(fields.Integer(string='Currency Digits'),
|
currency_digits = fields.Function(fields.Integer(string='Currency Digits',
|
||||||
'on_change_with_currency_digits')
|
readonly=True), 'on_change_with_currency_digits')
|
||||||
bookingtype = fields.Function(fields.Selection(string='Type', readonly=True,
|
bookingtype = fields.Function(fields.Selection(string='Type', readonly=True,
|
||||||
selection=sel_bookingtype), 'on_change_with_bookingtype')
|
selection=sel_bookingtype), 'on_change_with_bookingtype')
|
||||||
state = fields.Function(fields.Selection(string='State', readonly=True,
|
state = fields.Function(fields.Selection(string='State', readonly=True,
|
||||||
selection=sel_linetype), 'on_change_with_state')
|
selection=sel_linetype), 'on_change_with_state')
|
||||||
state_cashbook = fields.Function(fields.Selection(string='State of Cashbook',
|
state_cashbook = fields.Function(fields.Selection(string='State of Cashbook',
|
||||||
readonly=True, states={'invisible': True}, selection=sel_state_book),
|
readonly=True, states={'invisible': True}, selection=sel_state_book),
|
||||||
'on_change_with_state_cashbook', searcher='search_state_cashbook')
|
'on_change_with_state_cashbook')
|
||||||
|
|
||||||
|
def get_rec_name(self, name):
|
||||||
|
""" short + name
|
||||||
|
"""
|
||||||
|
return '%(type)s|%(amount)s %(symbol)s|%(desc)s [%(category)s]' % {
|
||||||
|
'desc': (self.description or '-')[:40],
|
||||||
|
'amount': Report.format_number(self.amount, None),
|
||||||
|
'symbol': getattr(self.currency, 'symbol', '-'),
|
||||||
|
'category': self.category_view,
|
||||||
|
'type': gettext('cashbook.msg_line_bookingtype_%s' % self.line.bookingtype),
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_amount_by_second_currency(self, to_currency):
|
||||||
|
""" get amount, calculate credit/debit from currency of current
|
||||||
|
cashbook to 'to_currency'
|
||||||
|
"""
|
||||||
|
Currency = Pool().get('currency.currency')
|
||||||
|
|
||||||
|
values = {
|
||||||
|
'amount': self.amount,
|
||||||
|
}
|
||||||
|
|
||||||
|
if to_currency.id != self.line.cashbook.currency.id:
|
||||||
|
with Transaction().set_context({
|
||||||
|
'date': self.line.date,
|
||||||
|
}):
|
||||||
|
values['amount'] = Currency.compute(
|
||||||
|
self.line.cashbook.currency,
|
||||||
|
self.amount,
|
||||||
|
to_currency)
|
||||||
|
return values
|
||||||
|
|
||||||
|
@fields.depends('category')
|
||||||
|
def on_change_with_category_view(self, name=None):
|
||||||
|
""" show optimizef form of category for list-view
|
||||||
|
"""
|
||||||
|
Configuration = Pool().get('cashbook.configuration')
|
||||||
|
|
||||||
|
if self.category:
|
||||||
|
cfg1 = Configuration.get_singleton()
|
||||||
|
|
||||||
|
if getattr(cfg1, 'catnamelong', True) == True:
|
||||||
|
return self.category.rec_name
|
||||||
|
else :
|
||||||
|
return self.category.name
|
||||||
|
|
||||||
@fields.depends('line', '_parent_line.state')
|
@fields.depends('line', '_parent_line.state')
|
||||||
def on_change_with_state(self, name=None):
|
def on_change_with_state(self, name=None):
|
||||||
|
@ -82,4 +131,51 @@ class SplitLine(ModelSQL, ModelView):
|
||||||
else:
|
else:
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, vlist):
|
||||||
|
""" add debit/credit
|
||||||
|
"""
|
||||||
|
Line2 = Pool().get('cashbook.line')
|
||||||
|
|
||||||
|
vlist = [x.copy() for x in vlist]
|
||||||
|
records = super(SplitLine, cls).create(vlist)
|
||||||
|
|
||||||
|
to_update_line = []
|
||||||
|
for record in records:
|
||||||
|
if not record.line in to_update_line:
|
||||||
|
to_update_line.append(record.line)
|
||||||
|
|
||||||
|
if len(to_update_line) > 0:
|
||||||
|
Line2.update_amount_by_splitlines(to_update_line)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def write(cls, *args):
|
||||||
|
""" deny update if cashbook.line!='open',
|
||||||
|
add or update debit/credit
|
||||||
|
"""
|
||||||
|
Line2 = Pool().get('cashbook.line')
|
||||||
|
|
||||||
|
actions = iter(args)
|
||||||
|
to_update_line = []
|
||||||
|
for records, values in zip(actions, actions):
|
||||||
|
Line2.check_permission_write([x.line for x in records])
|
||||||
|
|
||||||
|
if 'amount' in values.keys():
|
||||||
|
for record in records:
|
||||||
|
if not record.line in to_update_line:
|
||||||
|
to_update_line.append(record.line)
|
||||||
|
super(SplitLine, cls).write(*args)
|
||||||
|
|
||||||
|
if len(to_update_line) > 0:
|
||||||
|
Line2.update_amount_by_splitlines(to_update_line)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete(cls, splitlines):
|
||||||
|
""" deny delete if book is not 'open' or wf is not 'edit'
|
||||||
|
"""
|
||||||
|
Line2 = Pool().get('cashbook.line')
|
||||||
|
|
||||||
|
Line2.check_permission_delete([x.line for x in splitlines])
|
||||||
|
return super(SplitLine, cls).delete(splitlines)
|
||||||
|
|
||||||
# end SplitLine
|
# end SplitLine
|
||||||
|
|
|
@ -7,6 +7,7 @@ import unittest
|
||||||
from trytond.modules.cashbook.tests.test_type import TypeTestCase
|
from trytond.modules.cashbook.tests.test_type import TypeTestCase
|
||||||
from trytond.modules.cashbook.tests.test_book import BookTestCase
|
from trytond.modules.cashbook.tests.test_book import BookTestCase
|
||||||
from trytond.modules.cashbook.tests.test_line import LineTestCase
|
from trytond.modules.cashbook.tests.test_line import LineTestCase
|
||||||
|
from trytond.modules.cashbook.tests.test_splitline import SplitLineTestCase
|
||||||
from trytond.modules.cashbook.tests.test_config import ConfigTestCase
|
from trytond.modules.cashbook.tests.test_config import ConfigTestCase
|
||||||
from trytond.modules.cashbook.tests.test_category import CategoryTestCase
|
from trytond.modules.cashbook.tests.test_category import CategoryTestCase
|
||||||
from trytond.modules.cashbook.tests.test_reconciliation import ReconTestCase
|
from trytond.modules.cashbook.tests.test_reconciliation import ReconTestCase
|
||||||
|
@ -19,6 +20,7 @@ class CashbookTestCase(\
|
||||||
CategoryTestCase,\
|
CategoryTestCase,\
|
||||||
ConfigTestCase,\
|
ConfigTestCase,\
|
||||||
LineTestCase,
|
LineTestCase,
|
||||||
|
SplitLineTestCase,
|
||||||
BookTestCase,
|
BookTestCase,
|
||||||
TypeTestCase,
|
TypeTestCase,
|
||||||
):
|
):
|
||||||
|
|
109
tests/test_splitline.py
Normal file
109
tests/test_splitline.py
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
|
||||||
|
from trytond.pool import Pool
|
||||||
|
from trytond.transaction import Transaction
|
||||||
|
from trytond.exceptions import UserError
|
||||||
|
from datetime import date
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
|
||||||
|
class SplitLineTestCase(ModuleTestCase):
|
||||||
|
'Test split line module'
|
||||||
|
module = 'cashbook'
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_splitline_check_clear_by_bookingtype(self):
|
||||||
|
""" add book, line, category, set line to 'in',
|
||||||
|
then update to 'spin'
|
||||||
|
"""
|
||||||
|
pool = Pool()
|
||||||
|
Book = pool.get('cashbook.book')
|
||||||
|
Lines = pool.get('cashbook.line')
|
||||||
|
|
||||||
|
types = self.prep_type()
|
||||||
|
category1 = self.prep_category(cattype='in')
|
||||||
|
category2 = self.prep_category(name='Cat2', 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': 'Text 1',
|
||||||
|
'category': category1.id,
|
||||||
|
'bookingtype': 'in',
|
||||||
|
'amount': Decimal('1.0'),
|
||||||
|
'party': party.id,
|
||||||
|
}])],
|
||||||
|
}])
|
||||||
|
|
||||||
|
self.assertEqual(len(book.lines), 1)
|
||||||
|
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|1.00 usd|Text 1 [Cat1]')
|
||||||
|
self.assertEqual(book.lines[0].amount, Decimal('1.0'))
|
||||||
|
self.assertEqual(book.lines[0].category.rec_name, 'Cat1')
|
||||||
|
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[0]],
|
||||||
|
{
|
||||||
|
'bookingtype': 'spin',
|
||||||
|
'splitlines': [('create', [{
|
||||||
|
'amount': Decimal('5.0'),
|
||||||
|
'category': category1.id,
|
||||||
|
'description': 'line 1'
|
||||||
|
}, {
|
||||||
|
'amount': Decimal('2.0'),
|
||||||
|
'category': category2.id,
|
||||||
|
'description': 'line 2',
|
||||||
|
}])],
|
||||||
|
}])
|
||||||
|
|
||||||
|
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev/Sp|7.00 usd|Text 1 [-]')
|
||||||
|
self.assertEqual(book.lines[0].amount, Decimal('7.0'))
|
||||||
|
self.assertEqual(book.lines[0].category, None)
|
||||||
|
|
||||||
|
self.assertEqual(len(book.lines[0].splitlines), 2)
|
||||||
|
self.assertEqual(book.lines[0].splitlines[0].amount, Decimal('5.0'))
|
||||||
|
self.assertEqual(book.lines[0].splitlines[0].category.rec_name, 'Cat1')
|
||||||
|
self.assertEqual(book.lines[0].splitlines[0].description, 'line 1')
|
||||||
|
self.assertEqual(book.lines[0].splitlines[0].rec_name, 'Rev/Sp|5.00 usd|line 1 [Cat1]')
|
||||||
|
|
||||||
|
self.assertEqual(book.lines[0].splitlines[1].amount, Decimal('2.0'))
|
||||||
|
self.assertEqual(book.lines[0].splitlines[1].category.rec_name, 'Cat2')
|
||||||
|
self.assertEqual(book.lines[0].splitlines[1].description, 'line 2')
|
||||||
|
self.assertEqual(book.lines[0].splitlines[1].rec_name, 'Rev/Sp|2.00 usd|line 2 [Cat2]')
|
||||||
|
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[0]],
|
||||||
|
{
|
||||||
|
'splitlines': [('write',
|
||||||
|
[book.lines[0].splitlines[0]],
|
||||||
|
{
|
||||||
|
'amount': Decimal('3.5'),
|
||||||
|
})],
|
||||||
|
}])
|
||||||
|
self.assertEqual(book.lines[0].splitlines[0].amount, Decimal('3.5'))
|
||||||
|
self.assertEqual(book.lines[0].splitlines[1].amount, Decimal('2.0'))
|
||||||
|
self.assertEqual(book.lines[0].amount, Decimal('5.5'))
|
||||||
|
|
||||||
|
Lines.write(*[
|
||||||
|
[book.lines[0]],
|
||||||
|
{
|
||||||
|
'bookingtype': 'in',
|
||||||
|
'amount': Decimal('7.5'),
|
||||||
|
'category': category2.id,
|
||||||
|
}])
|
||||||
|
self.assertEqual(book.lines[0].rec_name, '05/01/2022|Rev|7.50 usd|Text 1 [Cat2]')
|
||||||
|
self.assertEqual(book.lines[0].category.rec_name, 'Cat2')
|
||||||
|
self.assertEqual(len(book.lines[0].splitlines), 0)
|
||||||
|
|
||||||
|
# end SplitLineTestCase
|
|
@ -34,20 +34,21 @@ full copyright notices and license terms. -->
|
||||||
<label name="category"/>
|
<label name="category"/>
|
||||||
<field name="category"/>
|
<field name="category"/>
|
||||||
<newline/>
|
<newline/>
|
||||||
|
|
||||||
<label name="booktransf"/>
|
<label name="booktransf"/>
|
||||||
<field name="booktransf"/>
|
<field name="booktransf"/>
|
||||||
<newline/>
|
<newline/>
|
||||||
|
|
||||||
<group name="description" colspan="4" col="1" string="Description" yexpand="1">
|
<notebook colspan="6">
|
||||||
<field name="description" yfill="1"/>
|
<page name="splitlines" col="1" string="Split booking lines">
|
||||||
</group>
|
<field name="splitlines"/>
|
||||||
<newline/>
|
</page>
|
||||||
|
<page name="description" col="1" string="Description">
|
||||||
<field name="splitlines" colspan="4" yexpand="1"/>
|
<field name="description"/>
|
||||||
<newline/>
|
</page>
|
||||||
<field name="references" colspan="4" yexpand="1"/>
|
<page name="references" col="1" string="References">
|
||||||
<newline/>
|
<field name="references"/>
|
||||||
|
</page>
|
||||||
|
</notebook>
|
||||||
|
|
||||||
<field name="owner_cashbook"/>
|
<field name="owner_cashbook"/>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
<!-- This file is part of the cashbook-module from m-ds for Tryton.
|
<!-- 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
|
The COPYRIGHT file at the top level of this repository contains the
|
||||||
full copyright notices and license terms. -->
|
full copyright notices and license terms. -->
|
||||||
<tree>
|
<tree editable="1">
|
||||||
<field name="line" tree_invisible="1"/>
|
<field name="line" tree_invisible="1"/>
|
||||||
<field name="category_view"/>
|
<field name="category"/>
|
||||||
<field name="description" expand="1"/>
|
<field name="description" expand="1"/>
|
||||||
<field name="amount" sum="Amount"/>
|
<field name="amount" sum="Amount"/>
|
||||||
<field name="currency"/>
|
<field name="currency"/>
|
||||||
|
|
Loading…
Reference in a new issue