From c423586d7847ca06ea159b4c89edf298b087b430 Mon Sep 17 00:00:00 2001 From: "ced@b2ck.com" Date: Sun, 6 Jan 2008 20:14:01 +0100 Subject: [PATCH] Add report objects --- trytond/init.sql | 2 +- trytond/ir/actions.py | 22 ++--- trytond/ir/actions.xml | 6 +- trytond/module.py | 2 + trytond/pooler.py | 14 ++- trytond/report/__init__.py | 1 + trytond/report/report.py | 137 +++++++++++++++++++++++++++++ trytond/report_service/__init__.py | 0 trytond/web_service/report.py | 74 +--------------- 9 files changed, 169 insertions(+), 89 deletions(-) create mode 100644 trytond/report/__init__.py create mode 100644 trytond/report/report.py delete mode 100644 trytond/report_service/__init__.py diff --git a/trytond/init.sql b/trytond/init.sql index 96eb9ea7ff..266346a8b9 100644 --- a/trytond/init.sql +++ b/trytond/init.sql @@ -77,7 +77,7 @@ INHERITS (ir_actions); CREATE TABLE ir_act_report ( model varchar(64) NOT NULL, report_name varchar(64) NOT NULL, - report_odt varchar(64), + report varchar(64), auto boolean default true, primary key(id) ) diff --git a/trytond/ir/actions.py b/trytond/ir/actions.py index 912282e79c..dc546a3a3a 100644 --- a/trytond/ir/actions.py +++ b/trytond/ir/actions.py @@ -68,8 +68,8 @@ class ActionKeyword(OSV): .read(cursor, user, action_keyword.action.id, context=context)) if action_keyword.action.type == 'ir.actions.report': - del res[-1]['report_odt_content_data'] - del res[-1]['report_odt_content'] + del res[-1]['report_content_data'] + del res[-1]['report_content'] return res ActionKeyword() @@ -102,21 +102,17 @@ class ActionsReport(OSV): 'type': fields.char('Report Type', size=32, required=True), 'model': fields.char('Model', size=64, required=True), 'report_name': fields.char('Internal Name', size=64, required=True), - 'report_odt': fields.Char('ODT path', size=128), - 'report_odt_content_data': fields.binary('ODT content'), - 'report_odt_content': fields.function(_report_content, + 'report': fields.Char('Path', size=128), + 'report_content_data': fields.binary('Content'), + 'report_content': fields.function(_report_content, fnct_inv=_report_content_inv, method=True, - type='binary', string='ODT content',), + type='binary', string='Content',), 'auto': fields.boolean('Automatic', required=True), - 'multi': fields.boolean('On multiple doc.', - help="If set to true, the action will not be displayed " \ - "on the right toolbar of a form views.") } _defaults = { 'type': lambda *a: 'ir.actions.report', - 'multi': lambda *a: False, 'auto': lambda *a: True, - 'report_odt_content': lambda *a: False, + 'report_content': lambda *a: False, } ActionsReport() @@ -215,13 +211,9 @@ class ActionsWizard(OSV): translate=True), 'type': fields.char('Action type', size=32, required=True), 'wiz_name': fields.char('Wizard name', size=64, required=True), - 'multi': fields.boolean('Action on multiple doc.', - help="If set to true, the wizard will not be displayed \n" \ - "on the right toolbar of a form views.") } _defaults = { 'type': lambda *a: 'ir.actions.wizard', - 'multi': lambda *a: False, } ActionsWizard() diff --git a/trytond/ir/actions.xml b/trytond/ir/actions.xml index afaadd2fc4..37f95f38b4 100644 --- a/trytond/ir/actions.xml +++ b/trytond/ir/actions.xml @@ -66,8 +66,9 @@
- - + + + ]]> @@ -81,6 +82,7 @@ + ]]> diff --git a/trytond/module.py b/trytond/module.py index c152e90638..426fcfe79d 100644 --- a/trytond/module.py +++ b/trytond/module.py @@ -170,6 +170,8 @@ def load_module_graph(cursor, graph, **kwargs): modules = pool.instanciate(module) pool_wizard = pooler.get_pool_wizard(cursor.dbname) wizards = pool_wizard.instanciate(module, pool) + pool_report = pooler.get_pool_report(cursor.dbname) + reports = pool_report.instanciate(module, pool) cursor.execute('SELECT state, demo FROM ir_module_module WHERE name = %s', (module,)) (package_state, package_demo) = (cursor.rowcount and cursor.fetchone()) \ diff --git a/trytond/pooler.py b/trytond/pooler.py index df6bacfeff..37728958a2 100644 --- a/trytond/pooler.py +++ b/trytond/pooler.py @@ -4,9 +4,10 @@ from netsvc import Logger, LOG_INFO _DB = {} _POOL = {} _POOL_WIZARD = {} +_POOL_REPORT = {} def get_db_and_pool(db_name, force_demo=False, update_module=False, - wizard=False): + wizard=False, report=False): if db_name in _DB: database = _DB[db_name] else: @@ -18,6 +19,7 @@ def get_db_and_pool(db_name, force_demo=False, update_module=False, if db_name in _POOL: pool = _POOL[db_name] pool_wizard = _POOL_WIZARD[db_name] + pool_report = _POOL_REPORT[db_name] else: Logger().notify_channel('pooler', LOG_INFO, 'Instanciate pooler for %s' % (db_name)) @@ -29,6 +31,10 @@ def get_db_and_pool(db_name, force_demo=False, update_module=False, pool_wizard = WizardService() _POOL_WIZARD[db_name] = pool_wizard + from report import ReportService + pool_report = ReportService() + _POOL_REPORT[db_name] = pool_report + from module import load_modules load_modules(database, force_demo, update_module) @@ -38,6 +44,8 @@ def get_db_and_pool(db_name, force_demo=False, update_module=False, pool.get('ir.cron').pool_jobs(database.dbname) if wizard: return database, pool_wizard + if report: + return database, pool_report return database, pool def restart_pool(db_name, force_demo=False, update_module=False): @@ -71,3 +79,7 @@ def get_pool(db_name, force_demo=False, update_module=False): def get_pool_wizard(db_name, force_demo=False, update_module=False): pool = get_db_and_pool(db_name, force_demo, update_module, wizard=True)[1] return pool + +def get_pool_report(db_name, force_demo=False, update_module=False): + pool = get_db_and_pool(db_name, force_demo, update_module, report=True)[1] + return pool diff --git a/trytond/report/__init__.py b/trytond/report/__init__.py new file mode 100644 index 0000000000..27ad548b90 --- /dev/null +++ b/trytond/report/__init__.py @@ -0,0 +1 @@ +from report import * diff --git a/trytond/report/report.py b/trytond/report/report.py new file mode 100644 index 0000000000..3cf738d125 --- /dev/null +++ b/trytond/report/report.py @@ -0,0 +1,137 @@ +"Report" +from trytond.netsvc import Service, service_exist, Logger, LOG_ERROR +from trytond import pooler +import copy +from xml import dom +from trytond.osv import ExceptORM, ExceptOSV, OSV +import sys +import base64 + +MODULE_LIST = [] +MODULE_CLASS_LIST = {} +CLASS_POOL = {} + + +class ReportService(Service): + + def __init__(self): + self.object_name_pool = {} + self.module_obj_list = {} + Service.__init__(self, 'report_proxy') + Service.join_group(self, 'web-services') + Service.export_method(self, self.execute) + + def execute_cr(self, cursor, user, report_name, ids, datas, context=None): + try: + report = pooler.get_pool_report(cursor.dbname).get(report_name) + if not report: + self.abort_response('Report Error', 'warning', + 'Report %s doesn\'t exist' % str(report_name)) + res = report.execute(cursor, user, ids, datas, context) + return res + except ExceptORM, inst: + self.abort_response(inst.name, 'warning', inst.value) + except ExceptOSV, inst: + self.abort_response(inst.name, inst.exc_type, inst.value) + except: + import traceback + tb_s = reduce(lambda x, y: x+y, traceback.format_exception( + sys.exc_type, sys.exc_value, sys.exc_traceback)) + Logger().notify_channel("web-services", LOG_ERROR, + 'Exception in call: ' + tb_s) + raise + + def execute(self, dbname, user, report_name, ids, datas, context=None): + cursor = pooler.get_db(dbname).cursor() + pool = pooler.get_pool_report(dbname) + try: + try: + res = pool.execute_cr(cursor, user, report_name, ids, datas, context) + cursor.commit() + except Exception: + cursor.rollback() + raise + finally: + cursor.close() + return res + + def add(self, name, object_name_inst): + """ + adds a new obj instance to the obj pool. + if it already existed, the instance is replaced + """ + if self.object_name_pool.has_key(name): + del self.object_name_pool[name] + self.object_name_pool[name] = object_name_inst + + module = str(object_name_inst.__class__)[6:] + module = module[:len(module)-1] + module = module.split('.')[0][2:] + self.module_obj_list.setdefault(module, []).append(object_name_inst) + + def get(self, name): + return self.object_name_pool.get(name, None) + + def instanciate(self, module, pool_obj): + res = [] + class_list = MODULE_CLASS_LIST.get(module, []) + for klass in class_list: + res.append(klass.create_instance(self, module, pool_obj)) + return res + +class Report(object): + _name = "" + + def __new__(cls): + for module in cls.__module__.split('.'): + if module != 'trytond' and module != 'addons': + break + if not hasattr(cls, '_module'): + cls._module = module + MODULE_CLASS_LIST.setdefault(cls._module, []).append(cls) + CLASS_POOL[cls._name] = cls + if module not in MODULE_LIST: + MODULE_LIST.append(cls._module) + return None + + def create_instance(cls, pool, module, pool_obj): + """ + try to apply inheritancy at the instanciation level and + put objs in the pool var + """ + if pool.get(cls._name): + parent_class = pool.get(cls._name).__class__ + nattr = {} + for i in ( + '_context', + ): + new = copy.copy(getattr(pool.get(cls._name), i)) + if hasattr(new, 'update'): + new.update(cls.__dict__.get(i, {})) + else: + new.extend(cls.__dict__.get(i, [])) + nattr[i] = new + cls = type(cls._name, (cls, parent_class), nattr) + + + obj = object.__new__(cls) + obj.__init__(pool, pool_obj) + return obj + + create_instance = classmethod(create_instance) + + def __init__(self, pool, pool_obj): + pool.add(self._name, self) + self.pool = pool_obj + super(Report, self).__init__() + + def execute(self, cursor, user, ids, datas, context=None): + action_report_obj = self.pool.get('ir.actions.report') + action_report_ids = action_report_obj.search(cursor, user, [ + ('report_name', '=', self._name) + ], context=context) + action_report = action_report_obj.browse(cursor, user, + action_report_ids[0], context=context) + #TODO add parser + type, data = 'odt', action_report.report_content + return (type, base64.encodestring(data)) diff --git a/trytond/report_service/__init__.py b/trytond/report_service/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/trytond/web_service/report.py b/trytond/web_service/report.py index c093073baa..cec0f559ee 100644 --- a/trytond/web_service/report.py +++ b/trytond/web_service/report.py @@ -1,10 +1,5 @@ from trytond.netsvc import Service, LocalService from trytond import security -import threading -import thread -from trytond import pooler -from trytond.config import CONFIG -import base64 class Report(Service): @@ -12,71 +7,10 @@ class Report(Service): def __init__(self, name='report'): Service.__init__(self, name) Service.join_group(self, 'web-services') - Service.export_method(self, self.report) - Service.export_method(self, self.report_get) - self._reports = {} - self.max_id = 0 - self.id_protect = threading.Semaphore() + Service.export_method(self, self.execute) - def report(self, database, user, passwd, object_name, ids, datas=None, + def execute(self, database, user, passwd, report_name, ids, datas=None, context=None): - if datas is None: - datas = {} - if context is None: - context = {} security.check(database, user, passwd) - - self.id_protect.acquire() - self.max_id += 1 - report_id = self.max_id - self.id_protect.release() - - self._reports[report_id] = { - 'user': user, - 'result': False, - 'state': False, - } - - def _go(report_id, user, ids, datas, context): - cursor = pooler.get_db(database).cursor() - obj = LocalService('report.' + object_name) - (result, format) = obj.create(cursor, user, ids, datas, context) - cursor.close() - self._reports[report_id]['result'] = result - self._reports[report_id]['format'] = format - self._reports[report_id]['state'] = True - return True - - thread.start_new_thread(_go, (report_id, user, ids, datas, context)) - return report_id - - def _check_report(self, report_id): - result = self._reports[report_id] - res = {'state': result['state']} - if res['state']: - if CONFIG['reportgz']: - import zlib - res2 = zlib.compress(result['result']) - res['code'] = 'zlib' - else: - #CHECKME: why is this needed??? - if isinstance(result['result'], unicode): - res2 = result['result'].encode('latin1', 'replace') - else: - res2 = result['result'] - if res2: - res['result'] = base64.encodestring(res2) - res['format'] = result['format'] - del self._reports[report_id] - return res - - def report_get(self, database, user, passwd, report_id): - security.check(database, user, passwd) - - if report_id in self._reports: - if self._reports[report_id]['uid'] == user: - return self._check_report(report_id) - else: - raise Exception, 'AccessDenied' - else: - raise Exception, 'ReportNotFound' + report = LocalService('report_proxy') + return report.execute(database, user, report_name, ids, datas, context)