add worker-based precalculation of cashbook-values
This commit is contained in:
parent
9ef465f40f
commit
5d8f924960
17 changed files with 1060 additions and 98 deletions
207
valuestore.py
Normal file
207
valuestore.py
Normal file
|
@ -0,0 +1,207 @@
|
|||
# -*- 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 sql.functions import CurrentTimestamp, DateTrunc
|
||||
from sql.aggregate import Count
|
||||
from sql.conditionals import Coalesce
|
||||
from trytond.model import ModelSQL, fields, Unique, Index
|
||||
from trytond.pool import Pool
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pyson import Eval, PYSON, PYSONEncoder, PYSONDecoder
|
||||
from trytond.model.modelstorage import EvalEnvironment
|
||||
from trytond.report import Report
|
||||
|
||||
|
||||
class ValueStore(ModelSQL):
|
||||
'Value Store'
|
||||
__name__ = 'cashbook.values'
|
||||
|
||||
cashbook = fields.Many2One(
|
||||
string='Cashbook', required=True, model_name='cashbook.book',
|
||||
ondelete='CASCADE')
|
||||
field_name = fields.Char(string='Field Name', required=True)
|
||||
numvalue = fields.Numeric(
|
||||
string='Value', digits=(16, Eval('valuedigits', 6)),
|
||||
depends=['valuedigits'])
|
||||
valuedigits = fields.Function(fields.Integer(
|
||||
string='Digits', readonly=True),
|
||||
'on_change_with_valuedigits')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ValueStore, cls).__setup__()
|
||||
t = cls.__table__()
|
||||
cls._sql_constraints.extend([
|
||||
('uniqu_field',
|
||||
Unique(t, t.cashbook, t.field_name),
|
||||
'cashbook.msg_value_exists_in_store'),
|
||||
])
|
||||
cls._sql_indexes.update({
|
||||
Index(
|
||||
t,
|
||||
(t.field_name, Index.Equality())),
|
||||
})
|
||||
|
||||
def get_rec_name(self, name):
|
||||
""" name, balance, state
|
||||
"""
|
||||
return '|'.join([
|
||||
'[' + getattr(self.cashbook, 'rec_name', '-') + ']',
|
||||
self.field_name or '-',
|
||||
Report.format_number(
|
||||
self.numvalue,
|
||||
None,
|
||||
digits=self.valuedigits or 2)
|
||||
if self.numvalue is not None else '-',
|
||||
str(self.valuedigits) if self.valuedigits is not None else '-'])
|
||||
|
||||
@fields.depends('cashbook', 'field_name')
|
||||
def on_change_with_valuedigits(self, name=None):
|
||||
""" get digits by field name
|
||||
"""
|
||||
Cashbook = Pool().get('cashbook.book')
|
||||
|
||||
if self.cashbook and self.field_name:
|
||||
fieldobj = Cashbook._fields.get(self.field_name, None)
|
||||
if fieldobj:
|
||||
digit = getattr(fieldobj, 'digits', (16, 6))[1]
|
||||
if isinstance(digit, PYSON):
|
||||
# execute pyson on linked record
|
||||
digit = PYSONDecoder(
|
||||
EvalEnvironment(self.cashbook, Cashbook)
|
||||
).decode(PYSONEncoder().encode(digit))
|
||||
return digit
|
||||
return 6
|
||||
|
||||
@classmethod
|
||||
def _maintenance_fields(cls):
|
||||
""" list of model and fieldnames,
|
||||
to daily update
|
||||
"""
|
||||
return ['balance']
|
||||
|
||||
@classmethod
|
||||
def maintenance_values(cls):
|
||||
""" update values by cron
|
||||
"""
|
||||
pool = Pool()
|
||||
Cashbook = pool.get('cashbook.book')
|
||||
tab_val = cls.__table__()
|
||||
tab_book = Cashbook.__table__()
|
||||
cursor = Transaction().connection.cursor()
|
||||
context = Transaction().context
|
||||
|
||||
# select records older than 'check_dt'
|
||||
check_dt = context.get('maintenance_date', None)
|
||||
if not check_dt:
|
||||
check_dt = DateTrunc('day', CurrentTimestamp())
|
||||
|
||||
# select records to update
|
||||
query = tab_val.select(
|
||||
tab_val.id,
|
||||
where=tab_val.field_name.in_(cls._maintenance_fields()) &
|
||||
(DateTrunc('day', Coalesce(
|
||||
tab_val.write_date,
|
||||
tab_val.create_date,
|
||||
'1990-01-01 00:00:00')) < check_dt))
|
||||
cursor.execute(*query)
|
||||
records = []
|
||||
for x in cursor.fetchall():
|
||||
cb = cls(x[0]).cashbook
|
||||
if cb not in records:
|
||||
records.append(cb)
|
||||
|
||||
# add records with missing fields in value-store
|
||||
num_fields = len(Cashbook.valuestore_fields())
|
||||
query = tab_book.join(
|
||||
tab_val,
|
||||
condition=tab_book.id == tab_val.cashbook,
|
||||
type_='LEFT OUTER',
|
||||
).select(
|
||||
tab_book.id,
|
||||
Count(tab_val.id).as_('num'),
|
||||
group_by=[tab_book.id],
|
||||
having=Count(tab_val.id) < num_fields)
|
||||
cursor.execute(*query)
|
||||
records.extend([Cashbook(x[0]) for x in cursor.fetchall()])
|
||||
|
||||
if records:
|
||||
Cashbook.valuestore_update_records([x for x in records])
|
||||
|
||||
@classmethod
|
||||
def get_book_by_line(cls, records):
|
||||
""" select books above current record to update
|
||||
records: cashbook.line
|
||||
"""
|
||||
Book = Pool().get('cashbook.book')
|
||||
|
||||
to_update = []
|
||||
if records:
|
||||
books = Book.search([
|
||||
('parent', 'parent_of', [x.cashbook.id for x in records])
|
||||
])
|
||||
to_update.extend([
|
||||
x for x in books
|
||||
if x not in to_update])
|
||||
return to_update
|
||||
|
||||
@classmethod
|
||||
def get_book_by_books(cls, records):
|
||||
""" select books above current record to update
|
||||
records: cashbook.book
|
||||
"""
|
||||
Book = Pool().get('cashbook.book')
|
||||
|
||||
to_update = []
|
||||
if records:
|
||||
books = Book.search([
|
||||
('parent', 'parent_of', [x.id for x in records])
|
||||
])
|
||||
to_update.extend([
|
||||
x for x in books
|
||||
if x not in to_update])
|
||||
return to_update
|
||||
|
||||
@classmethod
|
||||
def update_books(cls, books):
|
||||
""" get cashbooks to update, queue it
|
||||
"""
|
||||
Book = Pool().get('cashbook.book')
|
||||
|
||||
if books:
|
||||
Book.__queue__.valuestore_update_records(books)
|
||||
|
||||
@classmethod
|
||||
def update_values(cls, data):
|
||||
""" data: {'fieldname': {id1: value, id2: value, ...}, ...}
|
||||
"""
|
||||
to_write = []
|
||||
to_create = []
|
||||
|
||||
for name in data.keys():
|
||||
for record_id in data[name].keys():
|
||||
# get existing record
|
||||
records = cls.search([
|
||||
('cashbook', '=', record_id),
|
||||
('field_name', '=', name)])
|
||||
|
||||
if records:
|
||||
for record in records:
|
||||
to_write.extend([
|
||||
[record],
|
||||
{'numvalue': data[name][record_id]}])
|
||||
else:
|
||||
to_create.append({
|
||||
'cashbook': record_id,
|
||||
'field_name': name,
|
||||
'numvalue': data[name][record_id]})
|
||||
|
||||
if to_create:
|
||||
cls.create(to_create)
|
||||
if to_write:
|
||||
cls.write(*to_write)
|
||||
|
||||
# end ValueStore
|
Loading…
Add table
Add a link
Reference in a new issue