cashbook_report/line.py

393 lines
15 KiB
Python
Raw Normal View History

2022-11-04 09:17:31 +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.
from decimal import Decimal
from sql.aggregate import Sum
from trytond.model import ModelView, ModelSQL, fields
2024-01-13 14:08:20 +00:00
from trytond.pyson import Eval, Bool
2022-11-04 09:17:31 +00:00
from trytond.transaction import Transaction
from trytond.i18n import gettext
from trytond.exceptions import UserError
from trytond.pool import Pool
from .templates import cashbook_types, category_types, booktype_types
2022-11-04 09:17:31 +00:00
class EvaluationLine(ModelSQL, ModelView):
'Evaluation Line Relation'
__name__ = 'cashbook_report.eval_line'
2023-06-16 12:15:57 +00:00
evaluation = fields.Many2One(
string='Evaluation', required=True, ondelete='CASCADE',
2022-11-04 09:17:31 +00:00
model_name='cashbook_report.evaluation')
2023-06-16 12:15:57 +00:00
cashbook = fields.Many2One(
string='Cashbook', ondelete='CASCADE', model_name='cashbook.book',
2022-11-04 09:17:31 +00:00
states={
2024-01-13 14:08:20 +00:00
'required': Eval('eval_dtype1', '').in_(cashbook_types),
}, depends=['eval_dtype1'])
2023-06-16 12:15:57 +00:00
dtype = fields.Many2One(
string='Type', ondelete='CASCADE', model_name='cashbook.type',
2022-11-04 09:17:31 +00:00
states={
2024-01-13 14:08:20 +00:00
'required': Eval('eval_dtype1', '').in_(booktype_types),
}, depends=['eval_dtype1'])
2023-06-16 12:15:57 +00:00
currency = fields.Many2One(
string='Currency', ondelete='CASCADE', model_name='currency.currency',
2022-11-04 09:17:31 +00:00
states={
2024-01-13 14:08:20 +00:00
'required': Eval('eval_dtype1', '') == 'currencies',
}, depends=['eval_dtype1'])
2023-06-16 12:15:57 +00:00
category = fields.Many2One(
string='Category', ondelete='CASCADE',
2022-11-08 20:56:03 +00:00
model_name='cashbook.bookcategory',
states={
2024-01-13 14:08:20 +00:00
'required': Eval('eval_dtype1', '').in_(category_types),
}, depends=['eval_dtype1'])
# dtypes + currency of evaluation
eval_dtype1 = fields.Function(fields.Char(
string='Data type 1', readonly=True), 'on_change_with_eval_dtype1')
eval_dtype2 = fields.Function(fields.Char(
string='Data type 2', readonly=True), 'on_change_with_eval_dtype2')
eval_dtype3 = fields.Function(fields.Char(
string='Data type 3', readonly=True), 'on_change_with_eval_dtype3')
eval_dtype4 = fields.Function(fields.Char(
string='Data type 4', readonly=True), 'on_change_with_eval_dtype4')
eval_dtype5 = fields.Function(fields.Char(
string='Data type 5', readonly=True), 'on_change_with_eval_dtype5')
2023-06-16 12:15:57 +00:00
eval_currency = fields.Function(fields.Many2One(
model_name='currency.currency',
2022-11-04 09:17:31 +00:00
string="Currency", readonly=True), 'on_change_with_eval_currency')
2023-06-16 12:15:57 +00:00
currency_digits = fields.Function(fields.Integer(
string='Currency Digits', readonly=True),
'on_change_with_currency_digits')
2022-11-04 09:17:31 +00:00
2023-06-16 12:15:57 +00:00
name = fields.Function(fields.Char(
string='Name'), 'on_change_with_name', setter='set_name_data')
2022-11-04 10:54:46 +00:00
name_line = fields.Char(string='Name', states={'invisible': True})
2024-01-13 14:08:20 +00:00
value1 = fields.Function(fields.Numeric(
string='Value 1',
2022-11-04 09:17:31 +00:00
readonly=True, digits=(16, Eval('currency_digits', 2)),
depends=['currency_digits']),
2024-01-13 14:08:20 +00:00
'on_change_with_value1')
value2 = fields.Function(fields.Numeric(
string='Value 2',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': ~Bool(Eval('eval_dtype2', ''))},
depends=['currency_digits', 'eval_dtype2']),
'on_change_with_value2')
value3 = fields.Function(fields.Numeric(
string='Value 3',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': ~Bool(Eval('eval_dtype3', ''))},
depends=['currency_digits', 'eval_dtype3']),
'on_change_with_value3')
value4 = fields.Function(fields.Numeric(
string='Value 4',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': ~Bool(Eval('eval_dtype4', ''))},
depends=['currency_digits', 'eval_dtype4']),
'on_change_with_value4')
value5 = fields.Function(fields.Numeric(
string='Value 5',
readonly=True, digits=(16, Eval('currency_digits', 2)),
states={'invisible': ~Bool(Eval('eval_dtype5', ''))},
depends=['currency_digits', 'eval_dtype5']),
'on_change_with_value5')
2022-11-04 09:17:31 +00:00
2022-11-04 10:54:46 +00:00
@classmethod
def set_name_data(cls, lines, name, value):
""" store updated name
"""
2023-12-03 16:56:46 +00:00
cls.write(*[lines, {'name_line': value}])
2022-11-04 10:54:46 +00:00
2022-11-04 09:17:31 +00:00
@classmethod
def fields_view_get(cls, view_id, view_type='form'):
""" replace form-view-id
"""
pool = Pool()
ModelData = pool.get('ir.model.data')
Evaluation = pool.get('cashbook_report.evaluation')
context = Transaction().context
# get id of origin chart-form
form_id = ModelData.get_id('cashbook_report', 'evalline_view_graph')
# active_evaluation was added by tree_open-action
2022-11-04 09:17:31 +00:00
active_evaluation = context.get('active_evaluation', None)
# check if we are requested for our default form...
if (view_type == 'graph') and (view_id == form_id) and \
2023-06-16 12:15:57 +00:00
(active_evaluation is not None):
2022-11-04 09:17:31 +00:00
evaluation, = Evaluation.browse([active_evaluation])
if evaluation.ui_view_chart:
# ... switch to view, created by evaluation-config
view_id = evaluation.ui_view_chart.id
return super(EvaluationLine, cls).fields_view_get(
view_id=view_id, view_type=view_type)
2024-01-13 14:08:20 +00:00
@fields.depends('evaluation', '_parent_evaluation.dtype1')
def on_change_with_eval_dtype1(self, name=None):
""" get dtype1 from parent
2022-11-04 09:17:31 +00:00
"""
if self.evaluation:
2024-01-13 14:08:20 +00:00
return self.evaluation.dtype1
@fields.depends('evaluation', '_parent_evaluation.dtype2')
def on_change_with_eval_dtype2(self, name=None):
""" get dtype2 from parent
"""
if self.evaluation:
return self.evaluation.dtype2
@fields.depends('evaluation', '_parent_evaluation.dtype3')
def on_change_with_eval_dtype3(self, name=None):
""" get dtype3 from parent
"""
if self.evaluation:
return self.evaluation.dtype3
@fields.depends('evaluation', '_parent_evaluation.dtype4')
def on_change_with_eval_dtype4(self, name=None):
""" get dtype4 from parent
"""
if self.evaluation:
return self.evaluation.dtype4
@fields.depends('evaluation', '_parent_evaluation.dtype5')
def on_change_with_eval_dtype5(self, name=None):
""" get dtype5 from parent
"""
if self.evaluation:
return self.evaluation.dtype5
2022-11-04 09:17:31 +00:00
@fields.depends('evaluation', '_parent_evaluation.currency')
def on_change_with_eval_currency(self, name=None):
""" currency of evaluation
"""
if self.evaluation:
return self.evaluation.currency.id
@fields.depends('evaluation', '_parent_evaluation.currency')
def on_change_with_currency_digits(self, name=None):
""" currency-digits of evaluation
"""
if self.evaluation:
return self.evaluation.currency.digits
else:
return 2
2023-06-16 12:15:57 +00:00
@fields.depends(
2024-01-13 14:08:20 +00:00
'eval_dtype1', 'category', 'cashbook', 'dtype', 'currency',
2023-06-16 12:15:57 +00:00
'name_line')
2022-11-04 10:54:46 +00:00
def on_change_with_name(self, name=None):
""" get name of Type
"""
# prefer to use local stored name of line
if self.name_line:
if len(self.name_line) > 0:
return self.name_line
# otherwise use rec_name of linked record
2024-01-13 14:08:20 +00:00
if self.eval_dtype1:
dtype_sel = {'currencies': 'currency'}
2023-06-16 12:15:57 +00:00
dtype_sel.update({x: 'cashbook' for x in cashbook_types})
dtype_sel.update({x: 'category' for x in category_types})
dtype_sel.update({x: 'dtype' for x in booktype_types})
2022-11-04 10:54:46 +00:00
return getattr(
2024-01-13 14:08:20 +00:00
getattr(self, dtype_sel[self.eval_dtype1], None),
2022-11-04 10:54:46 +00:00
'rec_name', None)
def convert_to_evalcurrency(self, from_currency, amount):
""" convert amount to current evaluation-currency
"""
Currency = Pool().get('currency.currency')
exp = Decimal(Decimal(1) / 10 ** self.currency_digits)
if amount is None:
return Decimal('0.0')
return Currency.compute(
2023-12-03 16:56:46 +00:00
from_currency, amount, self.eval_currency).quantize(exp)
2022-11-04 09:17:31 +00:00
@classmethod
def validate(cls, records):
""" check parent record
"""
super(EvaluationLine, cls).validate(records)
for record in records:
2024-01-13 14:08:20 +00:00
if (record.evaluation.dtype1 not in cashbook_types) and \
2023-06-16 12:15:57 +00:00
(record.cashbook is not None):
2022-11-04 09:17:31 +00:00
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
2024-01-13 14:08:20 +00:00
typename=gettext('cashbook_report.msg_dtype_cashbooks')))
if (record.evaluation.dtype1 not in booktype_types) and \
2023-06-16 12:15:57 +00:00
(record.dtype is not None):
2022-11-04 09:17:31 +00:00
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
2024-01-13 14:08:20 +00:00
typename=gettext('cashbook_report.msg_dtype_types')))
if (record.evaluation.dtype1 != 'currencies') and \
2023-06-16 12:15:57 +00:00
(record.currency is not None):
2022-11-04 09:17:31 +00:00
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
2024-01-13 14:08:20 +00:00
typename=gettext('cashbook_report.msg_dtype_currencies')))
if (record.evaluation.dtype1 not in category_types) and \
2023-06-16 12:15:57 +00:00
(record.category is not None):
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
2024-01-13 14:08:20 +00:00
typename=gettext('cashbook_report.msg_dtype_categories')))
2022-11-04 09:17:31 +00:00
2024-01-13 14:08:20 +00:00
def get_value_by_query(self, query):
2022-11-08 20:56:03 +00:00
""" run 'query' on Lines, convert used
currencies to evaluation-currency
2022-11-04 09:17:31 +00:00
"""
pool = Pool()
Lines = pool.get('cashbook.line')
Cashbook = pool.get('cashbook.book')
Currency = pool.get('currency.currency')
tab_line = Lines.__table__()
tab_book = Cashbook.__table__()
cursor = Transaction().connection.cursor()
total_amount = Decimal('0.0')
2022-11-04 23:19:41 +00:00
with Transaction().set_context({
2023-06-16 12:15:57 +00:00
'_check_access': True}):
2022-11-08 20:56:03 +00:00
lines = Lines.search(query, query=True)
2022-11-04 23:19:41 +00:00
2023-06-16 12:15:57 +00:00
query = lines.join(
tab_line,
condition=lines.id == tab_line.id,
).join(
tab_book,
condition=tab_book.id == tab_line.cashbook,
2022-11-04 23:19:41 +00:00
).select(
tab_book.currency,
Sum(tab_line.credit - tab_line.debit).as_('balance'),
2023-12-03 16:56:46 +00:00
group_by=[tab_book.currency])
2022-11-04 23:19:41 +00:00
cursor.execute(*query)
2024-01-13 14:08:20 +00:00
records = cursor.fetchall()
2023-03-10 22:44:02 +00:00
2024-01-13 14:08:20 +00:00
for record in records:
(id_currency, bal1) = record
2022-11-04 23:19:41 +00:00
if bal1 is not None:
total_amount += self.convert_to_evalcurrency(
Currency(id_currency), bal1)
return total_amount
2022-11-04 09:17:31 +00:00
2022-11-08 20:56:03 +00:00
def get_value_cashbooks(self):
""" balance of cashbooks
"""
if self.cashbook:
return self.convert_to_evalcurrency(
2023-12-03 16:56:46 +00:00
self.cashbook.currency, self.cashbook.balance)
2022-11-08 20:56:03 +00:00
def get_value_categories(self):
""" get balance of bookings in categories
2022-11-04 09:17:31 +00:00
converted to currency of evaluation
"""
2022-11-08 20:56:03 +00:00
IrDate = Pool().get('ir.date')
2022-11-04 09:17:31 +00:00
2022-11-08 20:56:03 +00:00
if self.category is None:
2022-11-04 09:17:31 +00:00
return None
2024-01-13 14:08:20 +00:00
return self.get_value_by_query([
2022-11-08 20:56:03 +00:00
('cashbook.categories.id', '=', self.category.id),
2022-11-04 23:19:41 +00:00
('cashbook.state', '=', 'open'),
2023-12-03 16:56:46 +00:00
('date', '<=', IrDate.today())])
2022-11-04 23:19:41 +00:00
2022-11-08 20:56:03 +00:00
def get_value_types(self):
""" get balance of bookings in cashbooks by 'type',
converted to currency of evaluation
"""
IrDate = Pool().get('ir.date')
2022-11-04 23:19:41 +00:00
2022-11-08 20:56:03 +00:00
if self.dtype is None:
return None
2022-11-04 23:19:41 +00:00
2024-01-13 14:08:20 +00:00
return self.get_value_by_query([
2022-11-08 20:56:03 +00:00
('cashbook.btype.id', '=', self.dtype.id),
('cashbook.state', '=', 'open'),
2023-12-03 16:56:46 +00:00
('date', '<=', IrDate.today())])
2022-11-08 20:56:03 +00:00
def get_value_currencies(self):
""" get balance of bookings in cashbooks by 'currency',
converted to currency of evaluation
"""
IrDate = Pool().get('ir.date')
if self.currency is None:
return None
2024-01-13 14:08:20 +00:00
return self.get_value_by_query([
2022-11-08 20:56:03 +00:00
('cashbook.currency.id', '=', self.currency.id),
('cashbook.state', '=', 'open'),
2023-12-03 16:56:46 +00:00
('date', '<=', IrDate.today())])
2022-11-04 09:17:31 +00:00
2023-06-16 12:15:57 +00:00
@fields.depends(
2024-01-13 14:08:20 +00:00
'eval_dtype1', 'eval_currency', 'currency_digits',
'cashbook', '_parent_cashbook.currency', '_parent_cashbook.balance',
'category', '_parent_category.id',
'evaluation', '_parent_evaluation.id', 'dtype', 'currency')
def on_change_with_value1(self, name=None):
""" balance of value1
"""
if (self.evaluation is None) or (self.eval_currency is None) or \
(self.currency_digits is None) or (self.eval_dtype1 is None):
return None
return getattr(self, 'get_value_%s' % self.eval_dtype1)()
@fields.depends(
'eval_dtype2', 'eval_currency', 'currency_digits',
'cashbook', '_parent_cashbook.currency', '_parent_cashbook.balance',
'category', '_parent_category.id',
'evaluation', '_parent_evaluation.id', 'dtype', 'currency')
def on_change_with_value2(self, name=None):
""" balance of value2
"""
if (self.evaluation is None) or (self.eval_currency is None) or \
(self.currency_digits is None) or (self.eval_dtype2 is None):
return None
return getattr(self, 'get_value_%s' % self.eval_dtype2)()
@fields.depends(
'eval_dtype3', 'eval_currency', 'currency_digits',
'cashbook', '_parent_cashbook.currency', '_parent_cashbook.balance',
'category', '_parent_category.id',
'evaluation', '_parent_evaluation.id', 'dtype', 'currency')
def on_change_with_value3(self, name=None):
""" balance of value3
"""
if (self.evaluation is None) or (self.eval_currency is None) or \
(self.currency_digits is None) or (self.eval_dtype3 is None):
return None
return getattr(self, 'get_value_%s' % self.eval_dtype3)()
@fields.depends(
'eval_dtype4', 'eval_currency', 'currency_digits',
'cashbook', '_parent_cashbook.currency', '_parent_cashbook.balance',
'category', '_parent_category.id',
'evaluation', '_parent_evaluation.id', 'dtype', 'currency')
def on_change_with_value4(self, name=None):
""" balance of value4
"""
if (self.evaluation is None) or (self.eval_currency is None) or \
(self.currency_digits is None) or (self.eval_dtype4 is None):
return None
return getattr(self, 'get_value_%s' % self.eval_dtype4)()
@fields.depends(
'eval_dtype5', 'eval_currency', 'currency_digits',
2023-06-16 12:15:57 +00:00
'cashbook', '_parent_cashbook.currency', '_parent_cashbook.balance',
2022-11-08 20:56:03 +00:00
'category', '_parent_category.id',
2022-11-04 09:17:31 +00:00
'evaluation', '_parent_evaluation.id', 'dtype', 'currency')
2024-01-13 14:08:20 +00:00
def on_change_with_value5(self, name=None):
2022-11-04 09:17:31 +00:00
""" balance of cashbook
"""
2022-11-08 20:56:03 +00:00
if (self.evaluation is None) or (self.eval_currency is None) or \
2024-01-13 14:08:20 +00:00
(self.currency_digits is None) or (self.eval_dtype5 is None):
2022-11-08 20:56:03 +00:00
return None
2024-01-13 14:08:20 +00:00
return getattr(self, 'get_value_%s' % self.eval_dtype5)()
2022-11-04 09:17:31 +00:00
# end EvaluationLine