diff --git a/book.py b/book.py index 6853719..b0cb21f 100644 --- a/book.py +++ b/book.py @@ -10,15 +10,20 @@ from trytond.i18n import gettext from trytond.transaction import Transaction from trytond.pool import Pool from trytond.report import Report +from trytond.config import config from decimal import Decimal -from datetime import date, datetime +from datetime import date from sql.aggregate import Sum from sql.conditionals import Case 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 = { @@ -265,16 +270,6 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView): } 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 def get_balance_of_cashbook_sql(cls): """ sql for balance of a single cashbook @@ -365,12 +360,6 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView): cursor = Transaction().connection.cursor() 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 = { x:{y.id: Decimal('0.0') for y in cashbooks} for x in ['balance', 'balance_all', 'balance_ref']} @@ -390,26 +379,19 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView): query = [{ 'model': 'cashbook.line', 'query': [('cashbook.parent', 'child_of', [x.id])], - #'cachekey': CACHEKEY_CASHBOOK % x.id, }, { 'model': 'currency.currency.rate', '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()]) for x in cashbooks } # read from cache - logger.warning('## get_balance_cashbook-KEYS %(time)s' % { - 'time': datetime.now().isoformat(), - }) (todo_cashbook, result) = MemCache.read_from_cache( cashbooks, cache_keys, names, result) if len(todo_cashbook) == 0: - logger.warning('## get_balance_cashbook-HIT %(time)s' % { - 'time': datetime.now().isoformat(), - }) return result # query balances of cashbooks and sub-cashbooks @@ -446,9 +428,6 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView): record[2], record[5], record[3]) MemCache.store_result(cashbooks, cache_keys, result, todo_cashbook) - logger.warning('## get_balance_cashbook-END %(time)s' % { - 'time': datetime.now().isoformat(), - }) return result @fields.depends('btype') diff --git a/docs/settings.txt b/docs/settings.txt new file mode 100644 index 0000000..9febae1 --- /dev/null +++ b/docs/settings.txt @@ -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 diff --git a/line.py b/line.py index bb39527..9d2dddb 100644 --- a/line.py +++ b/line.py @@ -16,7 +16,6 @@ from sql.functions import DatePart from sql.conditionals import Case from .book import sel_state_book from .mixin import SecondCurrencyMixin, MemCacheIndexMx -from .model import CACHEKEY_CASHBOOK sel_payee = [ @@ -180,8 +179,6 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView): states={'invisible': True}, model_name='res.user'), 'on_change_with_owner_cashbook') - #image = fields.Binary... - @classmethod def __register__(cls, module_name): super(Line, cls).__register__(module_name) @@ -984,8 +981,6 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView): def create(cls, vlist): """ add debit/credit """ - MemCache = Pool().get('cashbook.memcache') - vlist = [x.copy() for x in vlist] for values in vlist: values.update(cls.add_values_from_splitlines(values)) @@ -1006,20 +1001,13 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView): 'descr': values.get('description', '-'), }, )) - records = 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 + return super(Line, cls).create(vlist) @classmethod def write(cls, *args): """ deny update if cashbook.line!='open', add or update debit/credit """ - MemCache = Pool().get('cashbook.memcache') - actions = iter(args) to_write = [] for lines, values in zip(actions, actions): @@ -1066,22 +1054,11 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView): 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 def delete(cls, lines): """ deny delete if book is not 'open' or wf is not 'edit' """ - MemCache = Pool().get('cashbook.memcache') - 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) # end Line diff --git a/model.py b/model.py index ac97cb7..7796ced 100644 --- a/model.py +++ b/model.py @@ -7,19 +7,25 @@ from trytond.model import MultiValueMixin, ValueMixin, fields, Unique, Model from trytond.transaction import Transaction from trytond.pool import Pool from trytond.cache import MemoryCache +from trytond.config import config from datetime import timedelta, datetime from decimal import Decimal from sql import With, Literal from sql.functions import Function 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_CASHBOOK = 'cashbook-%s' class ArrayAgg(Function): @@ -105,14 +111,8 @@ class MemCache(Model): for x in values.keys() if record.id in values[x].keys()} cls._cashbook_value_cache.set(cache_keys[record.id], copy.deepcopy(data)) - # ~ logger.info('memcache-VALUE-SET %(time)s key=%(key)s' % { - # ~ 'time': datetime.now().isoformat(), - # ~ 'key': cache_keys[record.id], - # ~ }) - cls._cashbook_value_cache.sync(Transaction()) - # ~ logger.info('memcache-VALUE-SYNC %(time)s' % { - # ~ 'time': datetime.now().isoformat(), - # ~ }) + if ENABLE_CACHESYNC == True: + cls._cashbook_value_cache.sync(Transaction()) @classmethod def store_value(cls, cache_key, values): @@ -121,10 +121,6 @@ class MemCache(Model): if ENABLE_CACHE == False: return 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 def read_from_cache(cls, records, cache_keys, names, result): @@ -145,15 +141,7 @@ class MemCache(Model): if result[name][record.id] is None: result[name][record.id] = Decimal('0.0') 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 : - # ~ logger.info('memcache-VALUE-READ-FAIL %(time)s key=%(key)s' % { - # ~ 'time': datetime.now().isoformat(), - # ~ 'key': cache_keys[record.id], - # ~ }) todo_records.append(record) return (todo_records, result) @@ -167,11 +155,6 @@ class MemCache(Model): if ENABLE_CACHE == False: 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.extend(addkeys) @@ -215,11 +198,6 @@ class MemCache(Model): if 'cachekey' in line.keys(): 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) @classmethod @@ -238,6 +216,8 @@ class MemCache(Model): def record_update(cls, cache_key, record): """ update cache-value """ + if ENABLE_CACHE == False: + return cls.store_value(cache_key, cls.genkey(record.id, record.write_date, record.create_date) if record is not None else None) diff --git a/setup.py b/setup.py index 15bd46d..ff59617 100644 --- a/setup.py +++ b/setup.py @@ -99,7 +99,7 @@ setup(name='%s_%s' % (PREFIX, MODULE), package_data={ 'trytond.modules.%s' % MODULE: (info.get('xml', []) + ['tryton.cfg', 'locale/*.po', 'tests/*.py', - 'view/*.xml', 'icon/*.svg', + 'view/*.xml', 'icon/*.svg', 'docs/*.txt', 'report/*.fods', 'versiondep.txt', 'README.rst']), }, diff --git a/tests/test_book.py b/tests/test_book.py index 37ca2dd..522c798 100644 --- a/tests/test_book.py +++ b/tests/test_book.py @@ -9,7 +9,6 @@ from trytond.transaction import Transaction from trytond.exceptions import UserError from datetime import date from decimal import Decimal -from trytond.modules.cashbook.model import CACHEKEY_CASHBOOK class BookTestCase(ModuleTestCase): @@ -190,11 +189,6 @@ class BookTestCase(ModuleTestCase): self.assertEqual(book.rec_name, 'Level 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.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() def test_book_deny_delete_open(self):