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 68996daac7..93494ede0a 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 5f9729799f..95c2cc0624 100644
--- a/trytond/module.py
+++ b/trytond/module.py
@@ -170,6 +170,8 @@ def load_module_graph(cursor, graph):
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)