remove logging, add config-settings for caching, add docs
This commit is contained in:
parent
03324d5944
commit
78f160bf0b
6 changed files with 47 additions and 96 deletions
41
book.py
41
book.py
|
@ -10,15 +10,20 @@ from trytond.i18n import gettext
|
||||||
from trytond.transaction import Transaction
|
from trytond.transaction import Transaction
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.report import Report
|
from trytond.report import Report
|
||||||
|
from trytond.config import config
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from datetime import date, datetime
|
from datetime import date
|
||||||
from sql.aggregate import Sum
|
from sql.aggregate import Sum
|
||||||
from sql.conditionals import Case
|
from sql.conditionals import Case
|
||||||
from .model import order_name_hierarchical, sub_ids_hierarchical, \
|
from .model import order_name_hierarchical, sub_ids_hierarchical, \
|
||||||
AnyInArray, CACHEKEY_CURRENCY, CACHEKEY_CASHBOOK
|
AnyInArray, CACHEKEY_CURRENCY
|
||||||
|
|
||||||
import logging
|
|
||||||
logger = logging.getLogger(__name__)
|
# enable/disable caching of cachekey for 'currency.rate'
|
||||||
|
if config.get('cashbook', 'cache_currency', default='yes').lower() in ['yes', '1', 'true']:
|
||||||
|
ENA_CURRKEY = True
|
||||||
|
else :
|
||||||
|
ENA_CURRKEY = False
|
||||||
|
|
||||||
|
|
||||||
STATES = {
|
STATES = {
|
||||||
|
@ -265,16 +270,6 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
|
||||||
}
|
}
|
||||||
return recname
|
return recname
|
||||||
|
|
||||||
# ~ def get_cachekeys_by_hierarchy(self):
|
|
||||||
# ~ """ generate keys for all cashbooks above us
|
|
||||||
# ~ """
|
|
||||||
# ~ CBook = Pool().get('cashbook.book')
|
|
||||||
|
|
||||||
# ~ return [CACHEKEY_CASHBOOK % x.id
|
|
||||||
# ~ for x in CBook.search([
|
|
||||||
# ~ ('parent', 'parent_of', [self.id]),
|
|
||||||
# ~ ], order=[('id', 'ASC')])]
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_balance_of_cashbook_sql(cls):
|
def get_balance_of_cashbook_sql(cls):
|
||||||
""" sql for balance of a single cashbook
|
""" sql for balance of a single cashbook
|
||||||
|
@ -365,12 +360,6 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
|
||||||
cursor = Transaction().connection.cursor()
|
cursor = Transaction().connection.cursor()
|
||||||
context = Transaction().context
|
context = Transaction().context
|
||||||
|
|
||||||
logger.warning('## get_balance_cashbook-GO %(time)s %(ids)s %(name)s' % {
|
|
||||||
'time': datetime.now().isoformat(),
|
|
||||||
'ids': str([x.id for x in cashbooks]),
|
|
||||||
'name': names,
|
|
||||||
})
|
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
x:{y.id: Decimal('0.0') for y in cashbooks}
|
x:{y.id: Decimal('0.0') for y in cashbooks}
|
||||||
for x in ['balance', 'balance_all', 'balance_ref']}
|
for x in ['balance', 'balance_all', 'balance_ref']}
|
||||||
|
@ -390,26 +379,19 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
|
||||||
query = [{
|
query = [{
|
||||||
'model': 'cashbook.line',
|
'model': 'cashbook.line',
|
||||||
'query': [('cashbook.parent', 'child_of', [x.id])],
|
'query': [('cashbook.parent', 'child_of', [x.id])],
|
||||||
#'cachekey': CACHEKEY_CASHBOOK % x.id,
|
|
||||||
}, {
|
}, {
|
||||||
'model': 'currency.currency.rate',
|
'model': 'currency.currency.rate',
|
||||||
'query': [('currency.id', '=', x.currency.id)],
|
'query': [('currency.id', '=', x.currency.id)],
|
||||||
'cachekey': CACHEKEY_CURRENCY % x.currency.id,
|
'cachekey' if ENA_CURRKEY else 'disabled': CACHEKEY_CURRENCY % x.currency.id,
|
||||||
}, ],
|
}, ],
|
||||||
addkeys = [query_date.isoformat()])
|
addkeys = [query_date.isoformat()])
|
||||||
for x in cashbooks
|
for x in cashbooks
|
||||||
}
|
}
|
||||||
|
|
||||||
# read from cache
|
# read from cache
|
||||||
logger.warning('## get_balance_cashbook-KEYS %(time)s' % {
|
|
||||||
'time': datetime.now().isoformat(),
|
|
||||||
})
|
|
||||||
(todo_cashbook, result) = MemCache.read_from_cache(
|
(todo_cashbook, result) = MemCache.read_from_cache(
|
||||||
cashbooks, cache_keys, names, result)
|
cashbooks, cache_keys, names, result)
|
||||||
if len(todo_cashbook) == 0:
|
if len(todo_cashbook) == 0:
|
||||||
logger.warning('## get_balance_cashbook-HIT %(time)s' % {
|
|
||||||
'time': datetime.now().isoformat(),
|
|
||||||
})
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# query balances of cashbooks and sub-cashbooks
|
# query balances of cashbooks and sub-cashbooks
|
||||||
|
@ -446,9 +428,6 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
|
||||||
record[2], record[5], record[3])
|
record[2], record[5], record[3])
|
||||||
|
|
||||||
MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook)
|
MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook)
|
||||||
logger.warning('## get_balance_cashbook-END %(time)s' % {
|
|
||||||
'time': datetime.now().isoformat(),
|
|
||||||
})
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@fields.depends('btype')
|
@fields.depends('btype')
|
||||||
|
|
21
docs/settings.txt
Normal file
21
docs/settings.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
settings in tytond.conf
|
||||||
|
|
||||||
|
[cashbook]
|
||||||
|
# enable caching of values, stores values between
|
||||||
|
# browser requests, speeds up the retrieval of data.
|
||||||
|
# default: yes
|
||||||
|
memcache = yes
|
||||||
|
|
||||||
|
# Enables synchronization of the cache between multiple
|
||||||
|
# server instances.
|
||||||
|
# default: yes
|
||||||
|
# Requires the setting :
|
||||||
|
# [cache]
|
||||||
|
# clean_timeout=0
|
||||||
|
sync = yes
|
||||||
|
|
||||||
|
# Enables caching of the cache key for currency rates.
|
||||||
|
# Reduces the time required to determine the cache
|
||||||
|
# key for currency values.
|
||||||
|
# default: yes
|
||||||
|
cache_currency = yes
|
25
line.py
25
line.py
|
@ -16,7 +16,6 @@ from sql.functions import DatePart
|
||||||
from sql.conditionals import Case
|
from sql.conditionals import Case
|
||||||
from .book import sel_state_book
|
from .book import sel_state_book
|
||||||
from .mixin import SecondCurrencyMixin, MemCacheIndexMx
|
from .mixin import SecondCurrencyMixin, MemCacheIndexMx
|
||||||
from .model import CACHEKEY_CASHBOOK
|
|
||||||
|
|
||||||
|
|
||||||
sel_payee = [
|
sel_payee = [
|
||||||
|
@ -180,8 +179,6 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
|
||||||
states={'invisible': True}, model_name='res.user'),
|
states={'invisible': True}, model_name='res.user'),
|
||||||
'on_change_with_owner_cashbook')
|
'on_change_with_owner_cashbook')
|
||||||
|
|
||||||
#image = fields.Binary...
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __register__(cls, module_name):
|
def __register__(cls, module_name):
|
||||||
super(Line, cls).__register__(module_name)
|
super(Line, cls).__register__(module_name)
|
||||||
|
@ -984,8 +981,6 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
|
||||||
def create(cls, vlist):
|
def create(cls, vlist):
|
||||||
""" add debit/credit
|
""" add debit/credit
|
||||||
"""
|
"""
|
||||||
MemCache = Pool().get('cashbook.memcache')
|
|
||||||
|
|
||||||
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.add_values_from_splitlines(values))
|
values.update(cls.add_values_from_splitlines(values))
|
||||||
|
@ -1006,20 +1001,13 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
|
||||||
'descr': values.get('description', '-'),
|
'descr': values.get('description', '-'),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
records = super(Line, cls).create(vlist)
|
return super(Line, cls).create(vlist)
|
||||||
|
|
||||||
# ~ for record in records:
|
|
||||||
# ~ for x in record.cashbook.get_cachekeys_by_hierarchy():
|
|
||||||
# ~ MemCache.record_update(x, record)
|
|
||||||
return records
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def write(cls, *args):
|
def write(cls, *args):
|
||||||
""" deny update if cashbook.line!='open',
|
""" deny update if cashbook.line!='open',
|
||||||
add or update debit/credit
|
add or update debit/credit
|
||||||
"""
|
"""
|
||||||
MemCache = Pool().get('cashbook.memcache')
|
|
||||||
|
|
||||||
actions = iter(args)
|
actions = iter(args)
|
||||||
to_write = []
|
to_write = []
|
||||||
for lines, values in zip(actions, actions):
|
for lines, values in zip(actions, actions):
|
||||||
|
@ -1066,22 +1054,11 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
|
||||||
|
|
||||||
super(Line, cls).write(*to_write)
|
super(Line, cls).write(*to_write)
|
||||||
|
|
||||||
# ~ actions = iter(to_write)
|
|
||||||
# ~ for records, values in zip(actions, actions):
|
|
||||||
# ~ for record in records:
|
|
||||||
# ~ for x in record.cashbook.get_cachekeys_by_hierarchy():
|
|
||||||
# ~ MemCache.record_update(x, record)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
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'
|
||||||
"""
|
"""
|
||||||
MemCache = Pool().get('cashbook.memcache')
|
|
||||||
|
|
||||||
cls.check_permission_delete(lines)
|
cls.check_permission_delete(lines)
|
||||||
# ~ for line in lines:
|
|
||||||
# ~ for x in line.cashbook.get_cachekeys_by_hierarchy():
|
|
||||||
# ~ MemCache.record_update(x, None)
|
|
||||||
super(Line, cls).delete(lines)
|
super(Line, cls).delete(lines)
|
||||||
|
|
||||||
# end Line
|
# end Line
|
||||||
|
|
48
model.py
48
model.py
|
@ -7,19 +7,25 @@ from trytond.model import MultiValueMixin, ValueMixin, fields, Unique, Model
|
||||||
from trytond.transaction import Transaction
|
from trytond.transaction import Transaction
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.cache import MemoryCache
|
from trytond.cache import MemoryCache
|
||||||
|
from trytond.config import config
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from sql import With, Literal
|
from sql import With, Literal
|
||||||
from sql.functions import Function
|
from sql.functions import Function
|
||||||
from sql.conditionals import Coalesce
|
from sql.conditionals import Coalesce
|
||||||
import copy, logging
|
import copy
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
if config.get('cashbook', 'memcache', default='yes').lower() in ['yes', '1', 'true']:
|
||||||
|
ENABLE_CACHE = True
|
||||||
|
else:
|
||||||
|
ENABLE_CACHE = False
|
||||||
|
|
||||||
|
if config.get('cashbook', 'sync', default='yes').lower() in ['yes', '1', 'true']:
|
||||||
|
ENABLE_CACHESYNC = True
|
||||||
|
else:
|
||||||
|
ENABLE_CACHESYNC = False
|
||||||
|
|
||||||
ENABLE_CACHE = True
|
|
||||||
CACHEKEY_CURRENCY = 'currency-%s'
|
CACHEKEY_CURRENCY = 'currency-%s'
|
||||||
CACHEKEY_CASHBOOK = 'cashbook-%s'
|
|
||||||
|
|
||||||
|
|
||||||
class ArrayAgg(Function):
|
class ArrayAgg(Function):
|
||||||
|
@ -105,14 +111,8 @@ class MemCache(Model):
|
||||||
for x in values.keys()
|
for x in values.keys()
|
||||||
if record.id in values[x].keys()}
|
if record.id in values[x].keys()}
|
||||||
cls._cashbook_value_cache.set(cache_keys[record.id], copy.deepcopy(data))
|
cls._cashbook_value_cache.set(cache_keys[record.id], copy.deepcopy(data))
|
||||||
# ~ logger.info('memcache-VALUE-SET %(time)s key=%(key)s' % {
|
if ENABLE_CACHESYNC == True:
|
||||||
# ~ 'time': datetime.now().isoformat(),
|
cls._cashbook_value_cache.sync(Transaction())
|
||||||
# ~ 'key': cache_keys[record.id],
|
|
||||||
# ~ })
|
|
||||||
cls._cashbook_value_cache.sync(Transaction())
|
|
||||||
# ~ logger.info('memcache-VALUE-SYNC %(time)s' % {
|
|
||||||
# ~ 'time': datetime.now().isoformat(),
|
|
||||||
# ~ })
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def store_value(cls, cache_key, values):
|
def store_value(cls, cache_key, values):
|
||||||
|
@ -121,10 +121,6 @@ class MemCache(Model):
|
||||||
if ENABLE_CACHE == False:
|
if ENABLE_CACHE == False:
|
||||||
return
|
return
|
||||||
cls._cashbook_value_cache.set(cache_key, copy.deepcopy(values))
|
cls._cashbook_value_cache.set(cache_key, copy.deepcopy(values))
|
||||||
# ~ logger.info('memcache-VALUE-SET %(time)s key=%(key)s' % {
|
|
||||||
# ~ 'time': datetime.now().isoformat(),
|
|
||||||
# ~ 'key': cache_key,
|
|
||||||
# ~ })
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def read_from_cache(cls, records, cache_keys, names, result):
|
def read_from_cache(cls, records, cache_keys, names, result):
|
||||||
|
@ -145,15 +141,7 @@ class MemCache(Model):
|
||||||
if result[name][record.id] is None:
|
if result[name][record.id] is None:
|
||||||
result[name][record.id] = Decimal('0.0')
|
result[name][record.id] = Decimal('0.0')
|
||||||
result[name][record.id] += values[name]
|
result[name][record.id] += values[name]
|
||||||
# ~ logger.info('memcache-VALUE-READ-HIT %(time)s key=%(key)s' % {
|
|
||||||
# ~ 'time': datetime.now().isoformat(),
|
|
||||||
# ~ 'key': cache_keys[record.id],
|
|
||||||
# ~ })
|
|
||||||
else :
|
else :
|
||||||
# ~ logger.info('memcache-VALUE-READ-FAIL %(time)s key=%(key)s' % {
|
|
||||||
# ~ 'time': datetime.now().isoformat(),
|
|
||||||
# ~ 'key': cache_keys[record.id],
|
|
||||||
# ~ })
|
|
||||||
todo_records.append(record)
|
todo_records.append(record)
|
||||||
return (todo_records, result)
|
return (todo_records, result)
|
||||||
|
|
||||||
|
@ -167,11 +155,6 @@ class MemCache(Model):
|
||||||
if ENABLE_CACHE == False:
|
if ENABLE_CACHE == False:
|
||||||
return '-'
|
return '-'
|
||||||
|
|
||||||
# ~ logger.info('memcache-KEY %(time)s name=%(name)s record=%(record)s' % {
|
|
||||||
# ~ 'time': datetime.now().isoformat(),
|
|
||||||
# ~ 'name': name,
|
|
||||||
# ~ 'record': str(record),
|
|
||||||
# ~ })
|
|
||||||
fname = [name, str(record.id)]
|
fname = [name, str(record.id)]
|
||||||
fname.extend(addkeys)
|
fname.extend(addkeys)
|
||||||
|
|
||||||
|
@ -215,11 +198,6 @@ class MemCache(Model):
|
||||||
|
|
||||||
if 'cachekey' in line.keys():
|
if 'cachekey' in line.keys():
|
||||||
key = cls.store_value(line['cachekey'], fname[-1])
|
key = cls.store_value(line['cachekey'], fname[-1])
|
||||||
# ~ logger.info('memcache-KEY-RESULT %(time)s name=%(name)s result=%(result)s' % {
|
|
||||||
# ~ 'time': datetime.now().isoformat(),
|
|
||||||
# ~ 'name': name,
|
|
||||||
# ~ 'result': '-'.join(fname),
|
|
||||||
# ~ })
|
|
||||||
return '-'.join(fname)
|
return '-'.join(fname)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -238,6 +216,8 @@ class MemCache(Model):
|
||||||
def record_update(cls, cache_key, record):
|
def record_update(cls, cache_key, record):
|
||||||
""" update cache-value
|
""" update cache-value
|
||||||
"""
|
"""
|
||||||
|
if ENABLE_CACHE == False:
|
||||||
|
return
|
||||||
cls.store_value(cache_key,
|
cls.store_value(cache_key,
|
||||||
cls.genkey(record.id, record.write_date, record.create_date)
|
cls.genkey(record.id, record.write_date, record.create_date)
|
||||||
if record is not None else None)
|
if record is not None else None)
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -99,7 +99,7 @@ setup(name='%s_%s' % (PREFIX, MODULE),
|
||||||
package_data={
|
package_data={
|
||||||
'trytond.modules.%s' % MODULE: (info.get('xml', [])
|
'trytond.modules.%s' % MODULE: (info.get('xml', [])
|
||||||
+ ['tryton.cfg', 'locale/*.po', 'tests/*.py',
|
+ ['tryton.cfg', 'locale/*.po', 'tests/*.py',
|
||||||
'view/*.xml', 'icon/*.svg',
|
'view/*.xml', 'icon/*.svg', 'docs/*.txt',
|
||||||
'report/*.fods', 'versiondep.txt', 'README.rst']),
|
'report/*.fods', 'versiondep.txt', 'README.rst']),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ from trytond.transaction import Transaction
|
||||||
from trytond.exceptions import UserError
|
from trytond.exceptions import UserError
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from trytond.modules.cashbook.model import CACHEKEY_CASHBOOK
|
|
||||||
|
|
||||||
|
|
||||||
class BookTestCase(ModuleTestCase):
|
class BookTestCase(ModuleTestCase):
|
||||||
|
@ -190,11 +189,6 @@ class BookTestCase(ModuleTestCase):
|
||||||
self.assertEqual(book.rec_name, 'Level 1')
|
self.assertEqual(book.rec_name, 'Level 1')
|
||||||
self.assertEqual(len(book.childs), 1)
|
self.assertEqual(len(book.childs), 1)
|
||||||
self.assertEqual(book.childs[0].rec_name, 'Level 1/Level 2 | 0.00 usd | Open')
|
self.assertEqual(book.childs[0].rec_name, 'Level 1/Level 2 | 0.00 usd | Open')
|
||||||
# ~ self.assertEqual(book.get_cachekeys_by_hierarchy(), [CACHEKEY_CASHBOOK % book.id])
|
|
||||||
# ~ self.assertEqual(book.childs[0].get_cachekeys_by_hierarchy(), [
|
|
||||||
# ~ CACHEKEY_CASHBOOK % book.id,
|
|
||||||
# ~ CACHEKEY_CASHBOOK % book.childs[0].id
|
|
||||||
# ~ ])
|
|
||||||
|
|
||||||
@with_transaction()
|
@with_transaction()
|
||||||
def test_book_deny_delete_open(self):
|
def test_book_deny_delete_open(self):
|
||||||
|
|
Loading…
Reference in a new issue