cashbook_report/evaluation.py
2022-10-31 13:57:39 +01:00

397 lines
13 KiB
Python

# -*- 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, Check
from trytond.pyson import Eval, Or, Bool, Id, Len
from trytond.transaction import Transaction
from trytond.i18n import gettext
from trytond.exceptions import UserError
from trytond.pool import Pool
from .colors import sel_color as sel_bgcolor
sel_etype = [
('cashbooks', 'Cashbooks'),
('types', 'Types of Cashbooks'),
('currencies', 'Currencys'),
#('category', 'Category'),
]
sel_chart = [
('vbar', 'Vertical Bars'),
('hbar', 'Horizontal Bars'),
('pie', 'Pie'),
('line', 'Line'),
]
sel_maincolor = [
('default', 'Default'),
('red', 'Red'),
('green', 'Green'),
('grey', 'Grey'),
('black', 'Black'),
('darkcyan', 'Dark Cyan'),
]
class Evaluation(ModelSQL, ModelView):
'Evaluation'
__name__ = 'cashbook_report.evaluation'
company = fields.Many2One(string='Company', model_name='company.company',
required=True, ondelete="RESTRICT")
name = fields.Char(string='Name', required=True)
dtype = fields.Selection(string='Data type', required=True,
sort=False, selection=sel_etype,
help='Type of data displayed')
chart = fields.Selection(string='Chart type', required=True,
sort=False, selection=sel_chart,
help='Type of graphical presentation.')
legend = fields.Boolean(string='Legend')
maincolor = fields.Selection(string='Color scheme', required=True,
help='The color scheme determines the hue of all components of the chart.',
selection=sel_maincolor, sort=False)
bgcolor = fields.Selection(string='Background Color', required=True,
help='Background color of the chart area.', sort=False,
selection=sel_bgcolor)
posted = fields.Boolean(string='Posted', help='Posted amounts only.')
currency = fields.Many2One(string='Currency', ondelete='RESTRICT',
model_name='currency.currency')
cashbooks = fields.Many2Many(string='Cashbooks',
relation_name='cashbook_report.eval_book',
origin='evaluation', target='cashbook',
states={
'invisible': Eval('dtype', '') != 'cashbooks',
}, depends=['dtype'])
types = fields.Many2Many(string='Types',
relation_name='cashbook_report.eval_type',
origin='evaluation', target='dtype',
states={
'invisible': Eval('dtype', '') != 'types',
}, depends=['dtype'])
currencies = fields.Many2Many(string='Currencies',
relation_name='cashbook_report.eval_currency',
origin='evaluation', target='currency',
filter=[('cashbook_hasbookings', '=', True)],
states={
'invisible': Eval('dtype', '') != 'currencies',
}, depends=['dtype'])
cashbook_values = fields.One2Many(string='Cashbook Values',
field='evaluation', readonly=True,
model_name='cashbook_report.eval_book')
currency_values = fields.One2Many(string='Currency Values',
field='evaluation', readonly=True,
model_name='cashbook_report.eval_currency')
type_values = fields.One2Many(string='Type Values',
field='evaluation', readonly=True,
model_name='cashbook_report.eval_type')
@classmethod
def default_currency(cls):
""" currency of company
"""
Company = Pool().get('company.company')
company = cls.default_company()
if company:
company = Company(company)
if company.currency:
return company.currency.id
@staticmethod
def default_company():
return Transaction().context.get('company') or None
@classmethod
def default_posted(cls):
""" default: False
"""
return False
@classmethod
def default_bgcolor(cls):
""" default: Yellow 5
"""
return '#ffffc0'
@classmethod
def default_maincolor(cls):
""" default: 'default'
"""
return 'default'
@classmethod
def default_legend(cls):
""" default True
"""
return True
@classmethod
def default_dtype(cls):
""" default 'book'
"""
return 'cashbooks'
@classmethod
def default_chart(cls):
""" default 'pie'
"""
return 'pie'
@classmethod
def write(cls, *args):
""" unlink records if dtype changes
"""
to_write = []
actions = iter(args)
for evaluations, values in zip(actions, actions):
if 'dtype' in values.keys():
for evaluation in evaluations:
if evaluation.dtype == values['dtype']:
continue
if (values['dtype'] != 'cashbooks') and \
(len(evaluation.cashbooks) > 0):
to_write.extend([
[evaluation],
{
'cashbooks': [
('remove', [x.id for x in evaluation.cashbooks])
],
}])
if (values['dtype'] != 'types') and (len(evaluation.types) > 0):
to_write.extend([
[evaluation],
{
'types': [
('remove', [x.id for x in evaluation.types])
],
}])
if (values['dtype'] != 'currencies') and (len(evaluation.currencies) > 0):
to_write.extend([
[evaluation],
{
'currencies': [
('remove', [x.id for x in evaluation.currencies])
],
}])
args = list(args)
args.extend(to_write)
super(Evaluation, cls).write(*args)
# end Evaluation
class RelFieldsMixin(object):
""" common fields
"""
evaluation = fields.Many2One(string='Evaluation', required=True,
select=True, ondelete='CASCADE',
model_name='cashbook_report.evaluation')
eval_currency = fields.Function(fields.Many2One(model_name='currency.currency',
string="Currency", readonly=True), 'on_change_with_eval_currency')
currency_digits = fields.Function(fields.Integer(string='Currency Digits',
readonly=True), 'on_change_with_currency_digits')
@fields.depends('evaluation', '_parent_evaluation.currency')
def on_change_with_eval_currency(self, name=None):
""" currency of cashbook
"""
if self.evaluation:
return self.evaluation.currency.id
@fields.depends('evaluation', '_parent_evaluation.currency')
def on_change_with_currency_digits(self, name=None):
""" currency of cashbook
"""
if self.evaluation:
return self.evaluation.currency.digits
else:
return 2
# end RelFieldsMixin
class EvaluationCashbookRel(RelFieldsMixin, ModelSQL):
'Evaluation Cashbook Relation'
__name__ = 'cashbook_report.eval_book'
cashbook = fields.Many2One(string='Cashbook', required=True,
select=True, ondelete='CASCADE',
model_name='cashbook.book')
name = fields.Function(fields.Char(string='Name', readonly=True),
'on_change_with_name')
balance = fields.Function(fields.Numeric(string='Balance',
readonly=True, digits=(16, Eval('currency_digits', 2)),
depends=['currency_digits']),
'on_change_with_balance')
@classmethod
def validate(cls, records):
""" check parent record
"""
super(EvaluationCashbookRel, cls).validate(records)
for record in records:
if record.evaluation.dtype != 'cashbooks':
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
typename = gettext('cashbook_report.msg_dtype_cashbook'),
))
@fields.depends('cashbook')
def on_change_with_name(self, name=None):
""" get name of Type
"""
if self.cashbook:
return self.cashbook.rec_name
@fields.depends('cashbook', '_parent_cashbook.currency', \
'_parent_cashbook.balance', 'eval_currency', 'currency_digits')
def on_change_with_balance(self, name=None):
""" balance of cashbook
"""
Currency = Pool().get('currency.currency')
if self.cashbook:
exp = Decimal(Decimal(1) / 10 ** self.currency_digits)
return Currency.compute(
self.cashbook.currency,
self.cashbook.balance,
self.eval_currency,
).quantize(exp)
# end EvaluationCashbookRel
class EvaluationTypeRel(RelFieldsMixin, ModelSQL):
'Evaluation Type Relation'
__name__ = 'cashbook_report.eval_type'
dtype = fields.Many2One(string='Type', required=True,
select=True, ondelete='CASCADE',
model_name='cashbook.type')
name = fields.Function(fields.Char(string='Name', readonly=True),
'on_change_with_name')
balance = fields.Function(fields.Numeric(string='Balance',
readonly=True, digits=(16, Eval('currency_digits', 2)),
depends=['currency_digits']),
'on_change_with_balance')
@classmethod
def validate(cls, records):
""" check parent record
"""
super(EvaluationTypeRel, cls).validate(records)
for record in records:
if record.evaluation.dtype != 'types':
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
typename = gettext('cashbook_report.msg_dtype_type'),
))
@fields.depends('dtype')
def on_change_with_name(self, name=None):
""" get name of Type
"""
if self.dtype:
return self.dtype.rec_name
@fields.depends('evaluation', 'eval_currency', 'currency_digits', 'dtype')
def on_change_with_balance(self, name=None):
""" get balanceof bookings in cashbooks by 'type',
converted to currency of evaluation
"""
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()
if (self.evaluation is None) or (self.dtype is None) or \
(self.eval_currency is None) or (self.currency_digits is None):
return None
lines = Lines.search([
('cashbook.btype.id', '=', self.dtype.id),
('cashbook.state', '=', 'open'),
('cashbook.owner.id', '=', Transaction().user),
], query=True)
query = lines.join(tab_line, condition=lines.id==tab_line.id,
).join(tab_book, condition=tab_book.id==tab_line.cashbook,
).select(
tab_book.currency,
Sum(tab_line.credit - tab_line.debit).as_('balance'),
group_by=[tab_book.currency],
)
cursor.execute(*query)
balances = cursor.fetchall()
total_amount = Decimal('0.0')
for balance in balances:
(id_currency, bal1) = balance
total_amount += Currency.compute(
Currency(id_currency),
bal1,
self.eval_currency,
)
exp = Decimal(Decimal(1) / 10 ** self.currency_digits)
return total_amount.quantize(exp)
# end EvaluationTypeRel
class EvaluationCurrencyRel(RelFieldsMixin, ModelSQL):
'Evaluation Currency Relation'
__name__ = 'cashbook_report.eval_currency'
currency = fields.Many2One(string='Currency', required=True,
select=True, ondelete='CASCADE',
model_name='currency.currency')
name = fields.Function(fields.Char(string='Name', readonly=True),
'on_change_with_name')
balance = fields.Function(fields.Numeric(string='Balance',
readonly=True, digits=(16, Eval('currency_digits', 2)),
depends=['currency_digits']),
'on_change_with_balance')
@classmethod
def validate(cls, records):
""" check parent record
"""
super(EvaluationCurrencyRel, cls).validate(records)
for record in records:
if record.evaluation.dtype != 'currencies':
raise UserError(gettext(
'cashbook_report.msg_invalid_dtype',
typename = gettext('cashbook_report.msg_dtype_currency'),
))
@fields.depends('currency')
def on_change_with_name(self, name=None):
""" get name of Type
"""
if self.currency:
return self.currency.rec_name
def on_change_with_balance(self, name=None):
""" balance of cashbook
"""
return None
# end EvaluationCurrencyRel