2022-08-05 14:47:43 +00:00
|
|
|
# -*- 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.
|
|
|
|
|
2022-08-08 12:31:42 +00:00
|
|
|
from trytond.model import ModelView, ModelSQL, Workflow, fields, Check
|
2022-08-05 14:47:43 +00:00
|
|
|
from trytond.pool import Pool
|
2022-08-11 09:06:28 +00:00
|
|
|
from trytond.pyson import Eval, If, Or, Bool
|
2022-08-05 14:47:43 +00:00
|
|
|
from trytond.transaction import Transaction
|
2022-08-08 12:31:42 +00:00
|
|
|
from trytond.report import Report
|
|
|
|
from trytond.exceptions import UserError
|
|
|
|
from trytond.i18n import gettext
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
from decimal import Decimal
|
2022-08-09 15:37:37 +00:00
|
|
|
from sql import Cast, Literal
|
|
|
|
from sql.functions import DatePart
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
from sql.conditionals import Case
|
2022-08-08 12:31:42 +00:00
|
|
|
from .book import sel_state_book
|
2022-08-05 14:47:43 +00:00
|
|
|
|
2022-08-09 13:08:41 +00:00
|
|
|
|
2022-08-16 12:16:14 +00:00
|
|
|
sel_payee = [
|
|
|
|
('cashbook.book', 'Cashbook'),
|
|
|
|
('party.party', 'Party')
|
|
|
|
]
|
|
|
|
|
2022-08-05 14:47:43 +00:00
|
|
|
sel_linetype = [
|
|
|
|
('edit', 'Edit'),
|
|
|
|
('check', 'Checked'),
|
|
|
|
('done', 'Done'),
|
|
|
|
]
|
|
|
|
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
sel_bookingtype = [
|
|
|
|
('in', 'Revenue'),
|
|
|
|
('out', 'Expense'),
|
|
|
|
('mvin', 'Transfer from'),
|
|
|
|
('mvout', 'Transfer to'),
|
|
|
|
]
|
|
|
|
|
2022-08-05 14:47:43 +00:00
|
|
|
STATES = {
|
2022-08-08 12:31:42 +00:00
|
|
|
'readonly': Or(
|
|
|
|
Eval('state', '') != 'edit',
|
|
|
|
Eval('state_cashbook', '') != 'open',
|
|
|
|
),
|
2022-08-05 14:47:43 +00:00
|
|
|
}
|
2022-08-08 12:31:42 +00:00
|
|
|
DEPENDS=['state', 'state_cashbook']
|
2022-08-05 14:47:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Line(Workflow, ModelSQL, ModelView):
|
2022-08-08 12:31:42 +00:00
|
|
|
'Cashbook Line'
|
2022-08-05 14:47:43 +00:00
|
|
|
__name__ = 'cashbook.line'
|
|
|
|
|
2022-08-08 12:31:42 +00:00
|
|
|
cashbook = fields.Many2One(string='Cashbook', required=True, select=True,
|
2022-08-05 14:47:43 +00:00
|
|
|
model_name='cashbook.book', ondelete='CASCADE', readonly=True)
|
|
|
|
date = fields.Date(string='Date', required=True, select=True,
|
|
|
|
states=STATES, depends=DEPENDS)
|
2022-08-09 15:37:37 +00:00
|
|
|
month = fields.Function(fields.Integer(string='Month', readonly=True),
|
|
|
|
'on_change_with_month', searcher='search_month')
|
2022-08-16 14:24:07 +00:00
|
|
|
number = fields.Char(string='Number', readonly=True)
|
2022-08-09 15:37:37 +00:00
|
|
|
description = fields.Text(string='Description',
|
|
|
|
states=STATES, depends=DEPENDS)
|
2022-08-16 12:16:14 +00:00
|
|
|
category = fields.Many2One(string='Category',
|
2022-08-09 15:37:37 +00:00
|
|
|
model_name='cashbook.category', ondelete='RESTRICT',
|
2022-08-11 09:06:28 +00:00
|
|
|
states={
|
|
|
|
'readonly': Or(
|
|
|
|
STATES['readonly'],
|
|
|
|
Bool(Eval('bookingtype')) == False,
|
|
|
|
),
|
2022-08-16 12:16:14 +00:00
|
|
|
'required': Eval('bookingtype', '').in_(['in', 'out']),
|
|
|
|
'invisible': ~Eval('bookingtype', '').in_(['in', 'out']),
|
2022-08-11 09:06:28 +00:00
|
|
|
}, depends=DEPENDS+['bookingtype'],
|
2022-08-10 15:06:20 +00:00
|
|
|
domain=[
|
|
|
|
If(
|
|
|
|
Eval('bookingtype', '').in_(['in', 'mvin']),
|
|
|
|
('cattype', '=', 'in'),
|
|
|
|
('cattype', '=', 'out'),
|
|
|
|
)])
|
2022-08-10 09:57:35 +00:00
|
|
|
category_view = fields.Function(fields.Char(string='Category', readonly=True),
|
|
|
|
'on_change_with_category_view', searcher='search_category_view')
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
|
|
|
|
bookingtype = fields.Selection(string='Type', required=True,
|
|
|
|
help='Type of Booking', selection=sel_bookingtype,
|
|
|
|
states=STATES, depends=DEPENDS)
|
|
|
|
amount = fields.Numeric(string='Amount', digits=(16, Eval('currency_digits', 2)),
|
|
|
|
required=True, states=STATES, depends=DEPENDS+['currency_digits'])
|
|
|
|
debit = fields.Numeric(string='Debit', digits=(16, Eval('currency_digits', 2)),
|
|
|
|
required=True, readonly=True, depends=['currency_digits'])
|
|
|
|
credit = fields.Numeric(string='Credit', digits=(16, Eval('currency_digits', 2)),
|
|
|
|
required=True, readonly=True, depends=['currency_digits'])
|
2022-08-15 15:19:53 +00:00
|
|
|
|
2022-08-16 12:16:14 +00:00
|
|
|
# party or cashbook as counterpart
|
|
|
|
booktransf = fields.Many2One(string='Source/Dest',
|
2022-08-15 15:19:53 +00:00
|
|
|
ondelete='RESTRICT', model_name='cashbook.book',
|
2022-08-16 12:16:14 +00:00
|
|
|
domain=[
|
|
|
|
('owner.id', '=', Eval('owner_cashbook', -1)),
|
|
|
|
('id', '!=', Eval('cashbook', -1)),
|
|
|
|
],
|
2022-08-15 15:19:53 +00:00
|
|
|
states={
|
|
|
|
'readonly': STATES['readonly'],
|
|
|
|
'invisible': ~Eval('bookingtype', '').in_(['mvin', 'mvout']),
|
|
|
|
'required': Eval('bookingtype', '').in_(['mvin', 'mvout']),
|
2022-08-16 12:16:14 +00:00
|
|
|
}, depends=DEPENDS+['bookingtype', 'owner_cashbook', 'cashbook'])
|
2022-08-15 15:19:53 +00:00
|
|
|
party = fields.Many2One(string='Party', model_name='party.party',
|
|
|
|
ondelete='RESTRICT',
|
|
|
|
states={
|
|
|
|
'readonly': STATES['readonly'],
|
|
|
|
'invisible': ~Eval('bookingtype', '').in_(['in', 'out']),
|
|
|
|
'required': Eval('bookingtype', '').in_(['in', 'out']),
|
|
|
|
}, depends=DEPENDS+['bookingtype'])
|
2022-08-16 12:16:14 +00:00
|
|
|
payee = fields.Function(fields.Reference(string='Payee', readonly=True,
|
|
|
|
selection=sel_payee), 'on_change_with_payee', searcher='search_payee')
|
|
|
|
|
|
|
|
# link to lines created by this record
|
|
|
|
reference = fields.Many2One(string='Reference', readonly=True, select=True,
|
|
|
|
states={
|
|
|
|
'invisible': ~Bool(Eval('reference')),
|
|
|
|
}, model_name='cashbook.line', ondelete='CASCADE',
|
|
|
|
help='The current row was created by and is controlled by the reference row.')
|
|
|
|
references = fields.One2Many(string='References', model_name='cashbook.line',
|
|
|
|
help='The rows are created and managed by the current record.',
|
|
|
|
states={
|
|
|
|
'invisible': ~Bool(Eval('references')),
|
|
|
|
}, field='reference', readonly=True)
|
2022-08-15 15:19:53 +00:00
|
|
|
|
2022-08-11 13:00:35 +00:00
|
|
|
reconciliation = fields.Many2One(string='Reconciliation', readonly=True,
|
2022-08-12 14:43:49 +00:00
|
|
|
model_name='cashbook.recon', ondelete='SET NULL',
|
|
|
|
domain=[('cashbook.id', '=', Eval('cashbook'))],
|
|
|
|
depends=['cashbook'])
|
2022-08-11 11:01:53 +00:00
|
|
|
|
|
|
|
balance = fields.Function(fields.Numeric(string='Balance',
|
|
|
|
digits=(16, Eval('currency_digits', 2)),
|
|
|
|
help='Balance of the cash book up to the current line, if the default sorting applies.',
|
|
|
|
readonly=True, depends=['currency_digits']),
|
|
|
|
'on_change_with_balance')
|
|
|
|
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
currency = fields.Function(fields.Many2One(model_name='currency.currency',
|
|
|
|
string="Currency"), 'on_change_with_currency')
|
|
|
|
currency_digits = fields.Function(fields.Integer(string='Currency Digits'),
|
|
|
|
'on_change_with_currency_digits')
|
|
|
|
|
2022-08-05 14:47:43 +00:00
|
|
|
state = fields.Selection(string='State', required=True, readonly=True,
|
|
|
|
select=True, selection=sel_linetype)
|
2022-08-08 12:31:42 +00:00
|
|
|
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')
|
2022-08-16 12:16:14 +00:00
|
|
|
owner_cashbook = fields.Function(fields.Many2One(string='Owner', readonly=True,
|
|
|
|
states={'invisible': True}, model_name='res.user'),
|
|
|
|
'on_change_with_owner_cashbook')
|
2022-08-05 14:47:43 +00:00
|
|
|
|
2022-08-09 13:08:41 +00:00
|
|
|
#image = fields.Binary...
|
|
|
|
|
2022-08-05 14:47:43 +00:00
|
|
|
@classmethod
|
|
|
|
def __setup__(cls):
|
|
|
|
super(Line, cls).__setup__()
|
|
|
|
cls._order.insert(0, ('date', 'ASC'))
|
2022-08-11 11:01:53 +00:00
|
|
|
cls._order.insert(0, ('state', 'ASC'))
|
2022-08-08 12:31:42 +00:00
|
|
|
t = cls.__table__()
|
|
|
|
cls._sql_constraints.extend([
|
|
|
|
('state_val',
|
|
|
|
Check(t, t.state.in_(['edit', 'check', 'done'])),
|
|
|
|
'cashbook.msg_line_wrong_state_value'),
|
|
|
|
])
|
2022-08-05 14:47:43 +00:00
|
|
|
cls._transitions |= set((
|
|
|
|
('edit', 'check'),
|
|
|
|
('check', 'done'),
|
|
|
|
('check', 'edit'),
|
|
|
|
))
|
|
|
|
cls._buttons.update({
|
|
|
|
'wfedit': {
|
|
|
|
'invisible': Eval('state', '') != 'check',
|
2022-08-16 12:16:14 +00:00
|
|
|
'readonly': Bool(Eval('reference')),
|
|
|
|
'depends': ['state', 'reference'],
|
2022-08-05 14:47:43 +00:00
|
|
|
},
|
|
|
|
'wfcheck': {
|
|
|
|
'invisible': Eval('state') != 'edit',
|
|
|
|
'depends': ['state'],
|
|
|
|
},
|
|
|
|
'wfdone': {
|
|
|
|
'invisible': Eval('state') != 'check',
|
|
|
|
'depends': ['state'],
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@ModelView.button
|
|
|
|
@Workflow.transition('edit')
|
|
|
|
def wfedit(cls, lines):
|
|
|
|
""" edit line
|
|
|
|
"""
|
2022-08-16 12:16:14 +00:00
|
|
|
pool = Pool()
|
|
|
|
Line2 = pool.get('cashbook.line')
|
|
|
|
|
|
|
|
to_delete_line = []
|
|
|
|
for line in lines:
|
|
|
|
if line.reference:
|
|
|
|
if Transaction().context.get('line.allow.wfedit', False) == False:
|
|
|
|
raise UserError(gettext(
|
|
|
|
'cashbook.msg_line_denywf_by_reference',
|
|
|
|
recname = line.reference.rec_name,
|
|
|
|
cbook = line.reference.cashbook.rec_name,
|
|
|
|
))
|
|
|
|
# delete references
|
|
|
|
to_delete_line.extend(list(line.references))
|
|
|
|
|
|
|
|
if len(to_delete_line) > 0:
|
|
|
|
with Transaction().set_context({
|
|
|
|
'line.allow.wfedit': True,
|
|
|
|
}):
|
|
|
|
Line2.wfedit(to_delete_line)
|
|
|
|
Line2.delete(to_delete_line)
|
2022-08-05 14:47:43 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@ModelView.button
|
|
|
|
@Workflow.transition('check')
|
|
|
|
def wfcheck(cls, lines):
|
|
|
|
""" line is checked
|
|
|
|
"""
|
2022-08-15 15:19:53 +00:00
|
|
|
pool = Pool()
|
|
|
|
Recon = pool.get('cashbook.recon')
|
2022-08-16 12:16:14 +00:00
|
|
|
Line2 = pool.get('cashbook.line')
|
2022-08-15 15:19:53 +00:00
|
|
|
|
2022-08-16 12:16:14 +00:00
|
|
|
to_create_line = []
|
2022-08-16 14:24:07 +00:00
|
|
|
to_write_line = []
|
2022-08-15 15:19:53 +00:00
|
|
|
for line in lines:
|
|
|
|
# deny if date is in range of existing reconciliation
|
|
|
|
# allow cashbook-line at range-limits
|
|
|
|
if Recon.search_count([
|
|
|
|
('state', 'in', ['check', 'done']),
|
|
|
|
('cashbook.id', '=', line.cashbook.id),
|
|
|
|
('date_from', '<', line.date),
|
|
|
|
('date_to', '>', line.date),
|
|
|
|
]) > 0:
|
|
|
|
raise UserError(gettext(
|
|
|
|
'cashbook.msg_line_err_write_to_reconciled',
|
|
|
|
datetxt = Report.format_date(line.date),
|
|
|
|
))
|
|
|
|
# deny if date is at reconciliation limits and two
|
|
|
|
# reconciliations exist
|
|
|
|
if Recon.search_count([
|
|
|
|
('state', 'in', ['check', 'done']),
|
|
|
|
('cashbook.id', '=', line.cashbook.id),
|
|
|
|
['OR',
|
|
|
|
('date_from', '=', line.date),
|
|
|
|
('date_to', '=', line.date),
|
|
|
|
]
|
|
|
|
]) > 1:
|
|
|
|
raise UserError(gettext(
|
|
|
|
'cashbook.msg_line_err_write_to_reconciled',
|
|
|
|
datetxt = Report.format_date(line.date),
|
|
|
|
))
|
2022-08-16 12:16:14 +00:00
|
|
|
# in case of 'mvin' or 'mvout' - create counterpart
|
|
|
|
if (line.bookingtype in ['mvout', 'mvin']) and (line.reference is None):
|
|
|
|
to_create_line.append({
|
|
|
|
'cashbook': line.booktransf.id,
|
|
|
|
'bookingtype': 'mvin' if line.bookingtype == 'mvout' else 'mvout',
|
|
|
|
'date': line.date,
|
|
|
|
'description': line.description,
|
|
|
|
'amount': line.amount,
|
|
|
|
'credit': line.debit,
|
|
|
|
'debit': line.credit,
|
|
|
|
'booktransf': line.cashbook.id,
|
|
|
|
'reference': line.id,
|
|
|
|
})
|
|
|
|
|
2022-08-16 14:24:07 +00:00
|
|
|
# add number to line
|
|
|
|
if line.cashbook.number_atcheck == True:
|
|
|
|
if len(line.number or '') == 0:
|
|
|
|
to_write_line.extend([
|
|
|
|
[line],
|
|
|
|
{
|
|
|
|
'number': line.cashbook.number_sequ.get()
|
|
|
|
}])
|
|
|
|
|
|
|
|
if len(to_write_line) > 0:
|
|
|
|
Line2.write(*to_write_line)
|
|
|
|
|
2022-08-16 12:16:14 +00:00
|
|
|
if len(to_create_line) > 0:
|
|
|
|
new_lines = Line2.create(to_create_line)
|
|
|
|
Line2.wfcheck(new_lines)
|
2022-08-05 14:47:43 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@ModelView.button
|
|
|
|
@Workflow.transition('done')
|
|
|
|
def wfdone(cls, lines):
|
|
|
|
""" line is done
|
|
|
|
"""
|
2022-08-16 14:24:07 +00:00
|
|
|
Line2 = Pool().get('cashbook.line')
|
|
|
|
|
|
|
|
to_write_line = []
|
|
|
|
for line in lines:
|
|
|
|
# add number to line
|
|
|
|
if len(line.number or '') == 0:
|
|
|
|
to_write_line.extend([
|
|
|
|
[line],
|
|
|
|
{
|
|
|
|
'number': line.cashbook.number_sequ.get()
|
|
|
|
}])
|
|
|
|
|
|
|
|
if len(to_write_line) > 0:
|
|
|
|
Line2.write(*to_write_line)
|
2022-08-05 14:47:43 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_state(cls):
|
|
|
|
""" default: edit
|
|
|
|
"""
|
|
|
|
return 'edit'
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_date(cls):
|
|
|
|
""" default: today
|
|
|
|
"""
|
|
|
|
IrDate = Pool().get('ir.date')
|
|
|
|
return IrDate.today()
|
|
|
|
|
|
|
|
@classmethod
|
2022-08-08 12:31:42 +00:00
|
|
|
def default_cashbook(cls):
|
2022-08-05 14:47:43 +00:00
|
|
|
""" get default from context
|
|
|
|
"""
|
|
|
|
context = Transaction().context
|
2022-08-08 12:31:42 +00:00
|
|
|
return context.get('cashbook', None)
|
|
|
|
|
2022-08-11 11:01:53 +00:00
|
|
|
@classmethod
|
|
|
|
def search_rec_name(cls, name, clause):
|
|
|
|
""" search in description +...
|
|
|
|
"""
|
|
|
|
return [('description',) + tuple(clause[1:])]
|
|
|
|
|
2022-08-08 12:31:42 +00:00
|
|
|
def get_rec_name(self, name):
|
|
|
|
""" short + name
|
|
|
|
"""
|
2022-08-16 12:16:14 +00:00
|
|
|
credit = self.credit if self.credit is not None else Decimal('0.0')
|
|
|
|
debit = self.debit if self.debit is not None else Decimal('0.0')
|
|
|
|
return '%(date)s|%(type)s|%(amount)s %(symbol)s|%(desc)s [%(category)s]' % {
|
2022-08-08 12:31:42 +00:00
|
|
|
'date': Report.format_date(self.date),
|
|
|
|
'desc': (self.description or '-')[:40],
|
2022-08-16 12:16:14 +00:00
|
|
|
'amount': Report.format_number(credit - debit, None),
|
2022-08-12 14:43:49 +00:00
|
|
|
'symbol': getattr(self.currency, 'symbol', '-'),
|
2022-08-16 12:16:14 +00:00
|
|
|
'category': self.category_view \
|
|
|
|
if self.bookingtype in ['in', 'out'] \
|
|
|
|
else getattr(self.booktransf, 'rec_name', '-'),
|
|
|
|
'type': gettext('cashbook.msg_line_bookingtype_%s' % self.bookingtype),
|
2022-08-08 12:31:42 +00:00
|
|
|
}
|
|
|
|
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
@staticmethod
|
|
|
|
def order_state(tables):
|
|
|
|
""" edit = 0, check/done = 1
|
|
|
|
"""
|
|
|
|
Line = Pool().get('cashbook.line')
|
|
|
|
tab_line = Line.__table__()
|
|
|
|
table, _ = tables[None]
|
|
|
|
|
|
|
|
query = tab_line.select(
|
|
|
|
Case(
|
|
|
|
(tab_line.state == 'edit', 1),
|
|
|
|
(tab_line.state.in_(['check', 'done']), 0),
|
|
|
|
else_ = 2),
|
|
|
|
where=tab_line.id==table.id
|
|
|
|
)
|
|
|
|
return [query]
|
|
|
|
|
2022-08-10 09:57:35 +00:00
|
|
|
@staticmethod
|
|
|
|
def order_category_view(tables):
|
|
|
|
""" order: name
|
|
|
|
"""
|
|
|
|
table, _ = tables[None]
|
|
|
|
Category = Pool().get('cashbook.category')
|
|
|
|
tab_cat = Category.__table__()
|
|
|
|
|
|
|
|
tab2 = tab_cat.select(tab_cat.name,
|
|
|
|
where=tab_cat.id==table.category
|
|
|
|
)
|
|
|
|
|
|
|
|
return [tab2]
|
|
|
|
|
2022-08-16 12:16:14 +00:00
|
|
|
@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']:
|
|
|
|
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
|
|
|
|
def search_payee(cls, names, clause):
|
|
|
|
""" search in payee for party or cashbook
|
|
|
|
"""
|
|
|
|
return ['OR',
|
|
|
|
('party.rec_name',) + tuple(clause[1:]),
|
|
|
|
('booktransf.rec_name',) + tuple(clause[1:]),
|
|
|
|
]
|
|
|
|
|
2022-08-10 09:57:35 +00:00
|
|
|
@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')
|
2022-08-15 10:35:31 +00:00
|
|
|
|
2022-08-10 09:57:35 +00:00
|
|
|
if self.category:
|
|
|
|
cfg1 = Configuration.get_singleton()
|
|
|
|
|
|
|
|
if getattr(cfg1, 'catnamelong', True) == True:
|
|
|
|
return self.category.rec_name
|
|
|
|
else :
|
2022-08-15 10:35:31 +00:00
|
|
|
return self.category.name
|
2022-08-10 09:57:35 +00:00
|
|
|
|
2022-08-08 12:31:42 +00:00
|
|
|
@classmethod
|
2022-08-11 11:01:53 +00:00
|
|
|
def search_category_view(cls, name, clause):
|
|
|
|
""" search in category
|
2022-08-08 12:31:42 +00:00
|
|
|
"""
|
2022-08-11 11:01:53 +00:00
|
|
|
return [('category.rec_name',) + tuple(clause[1:])]
|
2022-08-08 12:31:42 +00:00
|
|
|
|
2022-08-09 15:37:37 +00:00
|
|
|
@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
|
|
|
|
def search_month(cls, names, clause):
|
|
|
|
""" search in month
|
|
|
|
"""
|
|
|
|
pool = Pool()
|
|
|
|
Line = pool.get('cashbook.line')
|
|
|
|
IrDate = pool.get('ir.date')
|
|
|
|
tab_line = Line.__table__()
|
|
|
|
Operator = fields.SQL_OPERATORS[clause[1]]
|
|
|
|
|
|
|
|
dt1 = IrDate.today()
|
|
|
|
query = tab_line.select(tab_line.id,
|
|
|
|
where=Operator(
|
|
|
|
Literal(12 * dt1.year + dt1.month) - \
|
|
|
|
(Literal(12) * DatePart('year', tab_line.date) + DatePart('month', tab_line.date)),
|
|
|
|
clause[2]),
|
|
|
|
)
|
|
|
|
return [('id', 'in', query)]
|
|
|
|
|
2022-08-16 12:16:14 +00:00
|
|
|
@fields.depends('cashbook', '_parent_cashbook.owner')
|
|
|
|
def on_change_with_owner_cashbook(self, name=None):
|
|
|
|
""" get current owner
|
|
|
|
"""
|
|
|
|
if self.cashbook:
|
|
|
|
return self.cashbook.owner.id
|
|
|
|
|
2022-08-08 12:31:42 +00:00
|
|
|
@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:])]
|
|
|
|
|
2022-08-11 11:01:53 +00:00
|
|
|
@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
|
|
|
|
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
@fields.depends('cashbook', '_parent_cashbook.currency')
|
|
|
|
def on_change_with_currency(self, name=None):
|
|
|
|
""" currency of cashbook
|
|
|
|
"""
|
|
|
|
if self.cashbook:
|
|
|
|
return self.cashbook.currency.id
|
|
|
|
|
|
|
|
@fields.depends('cashbook', '_parent_cashbook.currency')
|
|
|
|
def on_change_with_currency_digits(self, name=None):
|
|
|
|
""" currency of cashbook
|
|
|
|
"""
|
|
|
|
if self.cashbook:
|
|
|
|
return self.cashbook.currency.digits
|
|
|
|
else:
|
|
|
|
return 2
|
|
|
|
|
2022-08-11 11:01:53 +00:00
|
|
|
@fields.depends('id', 'cashbook', '_parent_cashbook.start_balance', '_parent_cashbook.id')
|
|
|
|
def on_change_with_balance(self, name=None):
|
|
|
|
""" compute balance until current line, with current sort order
|
|
|
|
"""
|
|
|
|
Line = Pool().get('cashbook.line')
|
|
|
|
|
|
|
|
if self.cashbook:
|
|
|
|
balance = self.cashbook.start_balance
|
|
|
|
lines = Line.search([
|
|
|
|
('cashbook.id', '=', self.cashbook.id),
|
|
|
|
])
|
|
|
|
for line in lines:
|
|
|
|
balance += line.credit - line.debit
|
|
|
|
if line.id == self.id:
|
|
|
|
break
|
|
|
|
return balance
|
|
|
|
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
@classmethod
|
|
|
|
def get_debit_credit(cls, values):
|
|
|
|
""" compute debit/credit from amount
|
|
|
|
"""
|
|
|
|
if isinstance(values, dict):
|
|
|
|
type_ = values.get('bookingtype', None)
|
|
|
|
amount = values.get('amount', None)
|
|
|
|
else :
|
|
|
|
type_ = getattr(values, 'bookingtype', None)
|
|
|
|
amount = getattr(values, 'amount', None)
|
|
|
|
|
|
|
|
if type_:
|
|
|
|
if amount is not None:
|
|
|
|
if type_ in ['in', 'mvin']:
|
|
|
|
return {
|
|
|
|
'debit': Decimal('0.0'),
|
|
|
|
'credit': amount,
|
|
|
|
}
|
|
|
|
elif type_ in ['out', 'mvout']:
|
|
|
|
return {
|
|
|
|
'debit': amount,
|
|
|
|
'credit': Decimal('0.0'),
|
|
|
|
}
|
|
|
|
else :
|
|
|
|
raise ValueError('invalid "bookingtype"')
|
|
|
|
return {}
|
|
|
|
|
2022-08-16 14:24:07 +00:00
|
|
|
@classmethod
|
|
|
|
def copy(cls, lines, default=None):
|
|
|
|
""" reset values
|
|
|
|
"""
|
|
|
|
if default is None:
|
|
|
|
default = {}
|
|
|
|
else:
|
|
|
|
default = default.copy()
|
|
|
|
default.setdefault('number', None)
|
|
|
|
default.setdefault('state', cls.default_state())
|
|
|
|
return super(Line, cls).copy(moves, default=default)
|
|
|
|
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
@classmethod
|
|
|
|
def create(cls, vlist):
|
|
|
|
""" add debit/credit
|
|
|
|
"""
|
|
|
|
vlist = [x.copy() for x in vlist]
|
2022-08-12 14:43:49 +00:00
|
|
|
for values in vlist:
|
|
|
|
values.update(cls.get_debit_credit(values))
|
|
|
|
|
|
|
|
# deny add to reconciliation if state is not 'check' or 'done'
|
|
|
|
if values.get('reconciliation', None):
|
|
|
|
if not values.get('state', '-') in ['check', 'done']:
|
|
|
|
date_txt = '-'
|
|
|
|
if values.get('date', None):
|
|
|
|
date_txt = Report.format_date(values.get('date', None))
|
|
|
|
raise UserError(gettext(
|
|
|
|
'cashbook.msg_line_deny_recon_by_state',
|
|
|
|
recname = '%(date)s|%(descr)s' % {
|
|
|
|
'date': date_txt,
|
|
|
|
'descr': values.get('description', '-'),
|
|
|
|
},
|
|
|
|
))
|
|
|
|
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
return super(Line, cls).create(vlist)
|
|
|
|
|
2022-08-09 15:37:37 +00:00
|
|
|
@classmethod
|
|
|
|
def write(cls, *args):
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
""" deny update if cashbook.line!='open',
|
|
|
|
add or update debit/credit
|
2022-08-09 15:37:37 +00:00
|
|
|
"""
|
|
|
|
actions = iter(args)
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
to_write = []
|
2022-08-09 15:37:37 +00:00
|
|
|
for lines, values in zip(actions, actions):
|
|
|
|
for line in lines:
|
2022-08-12 14:43:49 +00:00
|
|
|
# deny write if chashbook is not open
|
2022-08-09 15:37:37 +00:00
|
|
|
if line.cashbook.state != 'open':
|
|
|
|
raise UserError(gettext(
|
|
|
|
'cashbook.msg_book_deny_write',
|
|
|
|
bookname = line.cashbook.rec_name,
|
|
|
|
state_txt = line.cashbook.state_string,
|
|
|
|
))
|
2022-08-12 14:43:49 +00:00
|
|
|
if line.reconciliation:
|
|
|
|
# deny state-change to 'edit' if line is linked to reconciliation
|
|
|
|
if values.get('state', '-') == 'edit':
|
|
|
|
raise UserError(gettext(
|
|
|
|
'cashbook.msg_line_deny_stateedit_with_recon',
|
|
|
|
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'
|
|
|
|
if values.get('reconciliation', None):
|
|
|
|
for line in lines:
|
|
|
|
if not line.state in ['check', 'done']:
|
|
|
|
raise UserError(gettext(
|
|
|
|
'cashbook.msg_line_deny_recon_by_state',
|
|
|
|
recname = line.rec_name
|
|
|
|
))
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
|
2022-08-12 14:43:49 +00:00
|
|
|
# update debit / credit
|
book, line, category, types: berechtigung für company-user + test,
book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
2022-08-10 14:30:08 +00:00
|
|
|
if len(set(values.keys()).intersection(set({'amount', 'bookingtype'}))) > 0:
|
|
|
|
for line in lines:
|
|
|
|
values2 = {}
|
|
|
|
values2.update(values)
|
|
|
|
values2.update(cls.get_debit_credit({
|
|
|
|
x:values.get(x, getattr(line, x)) for x in ['amount', 'bookingtype']
|
|
|
|
}))
|
|
|
|
to_write.extend([lines, values2])
|
|
|
|
else :
|
|
|
|
to_write.extend([lines, values])
|
|
|
|
super(Line, cls).write(*to_write)
|
2022-08-09 15:37:37 +00:00
|
|
|
|
2022-08-08 12:31:42 +00:00
|
|
|
@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)
|
2022-08-05 14:47:43 +00:00
|
|
|
|
|
|
|
# end Line
|
2022-08-10 09:57:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
class LineContext(ModelView):
|
|
|
|
'Line Context'
|
|
|
|
__name__ = 'cashbook.line.context'
|
|
|
|
|
|
|
|
cashbook = fields.Many2One(string='Cashbook', required=True,
|
|
|
|
model_name='cashbook.book',
|
|
|
|
states={
|
|
|
|
'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'),
|
|
|
|
('date_from', '<=', Eval('date_to')),
|
|
|
|
()),
|
|
|
|
])
|
|
|
|
date_to = fields.Date(string='End Date', depends=['date_from'],
|
|
|
|
domain=[
|
|
|
|
If(Eval('date_to') & Eval('date_from'),
|
|
|
|
('date_from', '<=', Eval('date_to')),
|
|
|
|
()),
|
|
|
|
])
|
|
|
|
checked = fields.Boolean(string='Checked',
|
|
|
|
help='Show account lines in Checked-state.')
|
|
|
|
done = fields.Boolean(string='Done',
|
|
|
|
help='Show account lines in Done-state.')
|
|
|
|
num_cashbook = fields.Function(fields.Integer(string='Number of Cashbook',
|
|
|
|
readonly=True, states={'invisible': True}),
|
|
|
|
'on_change_with_num_cashbook')
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_cashbook(cls):
|
|
|
|
""" get default from context
|
|
|
|
"""
|
|
|
|
context = Transaction().context
|
|
|
|
return context.get('cashbook', None)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_date_from(cls):
|
|
|
|
""" get default from context
|
|
|
|
"""
|
|
|
|
context = Transaction().context
|
|
|
|
return context.get('date_from', None)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_date_to(cls):
|
|
|
|
""" get default from context
|
|
|
|
"""
|
|
|
|
context = Transaction().context
|
|
|
|
return context.get('date_to', None)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_checked(cls):
|
|
|
|
""" get default from context
|
|
|
|
"""
|
|
|
|
context = Transaction().context
|
|
|
|
return context.get('checked', False)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_num_cashbook(cls):
|
|
|
|
""" get default from context
|
|
|
|
"""
|
|
|
|
CashBook = Pool().get('cashbook.book')
|
|
|
|
|
|
|
|
with Transaction().set_context({
|
|
|
|
'_check_access': True,
|
|
|
|
}):
|
|
|
|
return CashBook.search_count([])
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_done(cls):
|
|
|
|
""" get default from context
|
|
|
|
"""
|
|
|
|
context = Transaction().context
|
|
|
|
return context.get('done', False)
|
|
|
|
|
|
|
|
def on_change_with_num_cashbook(self, name=None):
|
|
|
|
""" get number of accessible cashbooks,
|
|
|
|
depends on user-permissions
|
|
|
|
"""
|
|
|
|
LineContext = Pool().get('cashbook.line.context')
|
|
|
|
return LineContext.default_num_cashbook()
|
|
|
|
|
|
|
|
# end LineContext
|