[MERGE] reports: make it possible to use only XML declaration, even with custom parsers.
This makes report registration more uniform, and report rendering be possible through the ORM (and thus the model service, instead of the report service). To register a report, always use the database, i.e. a <report> tag within an XML file. The custom parser, if any, will be specified in the database. Previously specify a custom parser, the report was declared in Python. Each model exposes a print_report() method, which will take the report name (as many report can be defined on a single model) in argument. bzr revid: vmt@openerp.com-20130327161129-6e7jz7l3lx7z1t18
This commit is contained in:
commit
23d672dfc3
|
@ -13,3 +13,4 @@ Modules
|
||||||
03_module_dev_04
|
03_module_dev_04
|
||||||
03_module_dev_05
|
03_module_dev_05
|
||||||
03_module_dev_06
|
03_module_dev_06
|
||||||
|
report-declaration
|
||||||
|
|
|
@ -6,6 +6,9 @@ Changelog
|
||||||
`trunk`
|
`trunk`
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Almost removed ``LocalService()``. For reports,
|
||||||
|
``openerp.osv.orm.Model.print_report()`` can be used. For workflows, see
|
||||||
|
:ref:`orm-workflows`.
|
||||||
- Removed support for the ``NET-RPC`` protocol.
|
- Removed support for the ``NET-RPC`` protocol.
|
||||||
- Added the :ref:`Long polling <longpolling-worker>` worker type.
|
- Added the :ref:`Long polling <longpolling-worker>` worker type.
|
||||||
- Added :ref:`orm-workflows` to the ORM.
|
- Added :ref:`orm-workflows` to the ORM.
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
.. _report-declaration:
|
||||||
|
|
||||||
|
Report declaration
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. versionadded:: 7.1
|
||||||
|
|
||||||
|
Before version 7.1, report declaration could be done in two different ways:
|
||||||
|
either via a ``<report>`` tag in XML, or via such a tag and a class
|
||||||
|
instanciation in a Python module. Instanciating a class in a Python module was
|
||||||
|
necessary when a custom parser was used.
|
||||||
|
|
||||||
|
In version 7.1, the recommended way to register a report is to use only the
|
||||||
|
``<report>`` XML tag. The tag can now support an additional ``parser``
|
||||||
|
attribute. The value for that attibute must be a fully-qualified class name,
|
||||||
|
without the leading ``openerp.addons.`` namespace.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
The rational to deprecate the manual class instanciation is to make all
|
||||||
|
reports visible in the database, have a unique way to declare reports
|
||||||
|
instead of two, and remove the need to maintain a registry of reports in
|
||||||
|
memory.
|
||||||
|
|
|
@ -20,11 +20,13 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import operator
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import openerp
|
||||||
from openerp import SUPERUSER_ID
|
from openerp import SUPERUSER_ID
|
||||||
from openerp import netsvc, tools
|
from openerp import netsvc, tools
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
|
@ -85,26 +87,45 @@ class report_xml(osv.osv):
|
||||||
res[report.id] = False
|
res[report.id] = False
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def register_all(self, cr):
|
def _lookup_report(self, cr, name):
|
||||||
"""Report registration handler that may be overridden by subclasses to
|
"""
|
||||||
add their own kinds of report services.
|
Look up a report definition.
|
||||||
Loads all reports with no manual loaders (auto==True) and
|
|
||||||
registers the appropriate services to implement them.
|
|
||||||
"""
|
"""
|
||||||
opj = os.path.join
|
opj = os.path.join
|
||||||
cr.execute("SELECT * FROM ir_act_report_xml WHERE auto=%s ORDER BY id", (True,))
|
|
||||||
result = cr.dictfetchall()
|
# First lookup in the deprecated place, because if the report definition
|
||||||
reports = openerp.report.interface.report_int._reports
|
# has not been updated, it is more likely the correct definition is there.
|
||||||
for r in result:
|
# Only reports with custom parser sepcified in Python are still there.
|
||||||
if reports.has_key('report.'+r['report_name']):
|
if 'report.' + name in openerp.report.interface.report_int._reports:
|
||||||
continue
|
new_report = openerp.report.interface.report_int._reports['report.' + name]
|
||||||
if r['report_rml'] or r['report_rml_content_data']:
|
else:
|
||||||
report_sxw('report.'+r['report_name'], r['model'],
|
cr.execute("SELECT * FROM ir_act_report_xml WHERE report_name=%s", (name,))
|
||||||
opj('addons',r['report_rml'] or '/'), header=r['header'])
|
r = cr.dictfetchone()
|
||||||
if r['report_xsl']:
|
if r:
|
||||||
report_rml('report.'+r['report_name'], r['model'],
|
if r['report_rml'] or r['report_rml_content_data']:
|
||||||
opj('addons',r['report_xml']),
|
if r['parser']:
|
||||||
r['report_xsl'] and opj('addons',r['report_xsl']))
|
kwargs = { 'parser': operator.attrgetter(r['parser'])(openerp.addons) }
|
||||||
|
else:
|
||||||
|
kwargs = {}
|
||||||
|
new_report = report_sxw('report.'+r['report_name'], r['model'],
|
||||||
|
opj('addons',r['report_rml'] or '/'), header=r['header'], register=False, **kwargs)
|
||||||
|
elif r['report_xsl']:
|
||||||
|
new_report = report_rml('report.'+r['report_name'], r['model'],
|
||||||
|
opj('addons',r['report_xml']),
|
||||||
|
r['report_xsl'] and opj('addons',r['report_xsl']), register=False)
|
||||||
|
else:
|
||||||
|
raise Exception, "Unhandled report type: %s" % r
|
||||||
|
else:
|
||||||
|
raise Exception, "Required report does not exist: %s" % r
|
||||||
|
|
||||||
|
return new_report
|
||||||
|
|
||||||
|
def render_report(self, cr, uid, res_ids, name, data, context=None):
|
||||||
|
"""
|
||||||
|
Look up a report definition and render the report for the provided IDs.
|
||||||
|
"""
|
||||||
|
new_report = self._lookup_report(cr, name)
|
||||||
|
return new_report.create(cr, uid, res_ids, data, context)
|
||||||
|
|
||||||
_name = 'ir.actions.report.xml'
|
_name = 'ir.actions.report.xml'
|
||||||
_inherit = 'ir.actions.actions'
|
_inherit = 'ir.actions.actions'
|
||||||
|
@ -140,6 +161,7 @@ class report_xml(osv.osv):
|
||||||
'report_sxw_content': fields.function(_report_content, fnct_inv=_report_content_inv, type='binary', string='SXW Content',),
|
'report_sxw_content': fields.function(_report_content, fnct_inv=_report_content_inv, type='binary', string='SXW Content',),
|
||||||
'report_rml_content': fields.function(_report_content, fnct_inv=_report_content_inv, type='binary', string='RML Content'),
|
'report_rml_content': fields.function(_report_content, fnct_inv=_report_content_inv, type='binary', string='RML Content'),
|
||||||
|
|
||||||
|
'parser': fields.char('Parser Class'),
|
||||||
}
|
}
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'type': 'ir.actions.report.xml',
|
'type': 'ir.actions.report.xml',
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
<group string="Miscellaneous">
|
<group string="Miscellaneous">
|
||||||
<field name="multi"/>
|
<field name="multi"/>
|
||||||
<field name="auto"/>
|
<field name="auto"/>
|
||||||
|
<field name="parser"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
|
|
|
@ -26,6 +26,8 @@ additional code is needed throughout the core library. This module keeps
|
||||||
track of those specific measures by providing variables that can be unset
|
track of those specific measures by providing variables that can be unset
|
||||||
by the user to check if her code is future proof.
|
by the user to check if her code is future proof.
|
||||||
|
|
||||||
|
In a perfect world, all these variables are set to False, the corresponding
|
||||||
|
code removed, and thus these variables made unnecessary.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# If True, the Python modules inside the openerp namespace are made available
|
# If True, the Python modules inside the openerp namespace are made available
|
||||||
|
@ -35,4 +37,20 @@ by the user to check if her code is future proof.
|
||||||
# Change to False around 2013.02.
|
# Change to False around 2013.02.
|
||||||
open_openerp_namespace = False
|
open_openerp_namespace = False
|
||||||
|
|
||||||
|
# If True, openerp.netsvc.LocalService() can be used to lookup reports or to
|
||||||
|
# access openerp.workflow.
|
||||||
|
# Introduced around 2013.03.
|
||||||
|
# Among the related code:
|
||||||
|
# - The openerp.netsvc.LocalService() function.
|
||||||
|
# - The openerp.report.interface.report_int._reports dictionary.
|
||||||
|
# - The register attribute in openerp.report.interface.report_int (and in its
|
||||||
|
# - auto column in ir.actions.report.xml.
|
||||||
|
# inheriting classes).
|
||||||
|
allow_local_service = True
|
||||||
|
|
||||||
|
# Applies for the register attribute in openerp.report.interface.report_int.
|
||||||
|
# See comments for allow_local_service above.
|
||||||
|
# Introduced around 2013.03.
|
||||||
|
allow_report_int_registration = True
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -107,6 +107,7 @@
|
||||||
<rng:optional><rng:attribute name="sxw"/></rng:optional>
|
<rng:optional><rng:attribute name="sxw"/></rng:optional>
|
||||||
<rng:optional><rng:attribute name="xml"/></rng:optional>
|
<rng:optional><rng:attribute name="xml"/></rng:optional>
|
||||||
<rng:optional><rng:attribute name="xsl"/></rng:optional>
|
<rng:optional><rng:attribute name="xsl"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="parser"/></rng:optional>
|
||||||
<rng:optional> <rng:attribute name="auto" /> </rng:optional>
|
<rng:optional> <rng:attribute name="auto" /> </rng:optional>
|
||||||
<rng:optional> <rng:attribute name="header" /> </rng:optional>
|
<rng:optional> <rng:attribute name="header" /> </rng:optional>
|
||||||
<rng:optional> <rng:attribute name="webkit_header" /> </rng:optional>
|
<rng:optional> <rng:attribute name="webkit_header" /> </rng:optional>
|
||||||
|
|
|
@ -36,8 +36,6 @@ from openerp.tools.safe_eval import safe_eval as eval
|
||||||
import openerp.pooler as pooler
|
import openerp.pooler as pooler
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
import openerp.netsvc as netsvc
|
|
||||||
|
|
||||||
import zipfile
|
import zipfile
|
||||||
import openerp.release as release
|
import openerp.release as release
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,6 @@ from openerp.tools.safe_eval import safe_eval as eval
|
||||||
import openerp.pooler as pooler
|
import openerp.pooler as pooler
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
import openerp.netsvc as netsvc
|
|
||||||
|
|
||||||
import zipfile
|
import zipfile
|
||||||
import openerp.release as release
|
import openerp.release as release
|
||||||
|
|
||||||
|
|
|
@ -225,7 +225,6 @@ class RegistryManager(object):
|
||||||
try:
|
try:
|
||||||
Registry.setup_multi_process_signaling(cr)
|
Registry.setup_multi_process_signaling(cr)
|
||||||
registry.do_parent_store(cr)
|
registry.do_parent_store(cr)
|
||||||
registry.get('ir.actions.report.xml').register_all(cr)
|
|
||||||
cr.commit()
|
cr.commit()
|
||||||
finally:
|
finally:
|
||||||
cr.close()
|
cr.close()
|
||||||
|
|
|
@ -21,11 +21,9 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
|
||||||
import errno
|
|
||||||
import logging
|
import logging
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import release
|
import release
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
@ -46,12 +44,30 @@ import openerp
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def LocalService(name):
|
def LocalService(name):
|
||||||
# Special case for addons support, will be removed in a few days when addons
|
"""
|
||||||
# are updated to directly use openerp.osv.osv.service.
|
The openerp.netsvc.LocalService() function is deprecated. It still works
|
||||||
|
in two cases: workflows and reports. For workflows, instead of using
|
||||||
|
LocalService('workflow'), openerp.workflow should be used (better yet,
|
||||||
|
methods on openerp.osv.orm.Model should be used). For reports,
|
||||||
|
openerp.report.render_report() should be used (methods on the Model should
|
||||||
|
be provided too in the future).
|
||||||
|
"""
|
||||||
|
assert openerp.conf.deprecation.allow_local_service
|
||||||
|
_logger.warning("LocalService() is deprecated since march 2013 (it was called with '%s')." % name)
|
||||||
|
|
||||||
if name == 'workflow':
|
if name == 'workflow':
|
||||||
return openerp.workflow
|
return openerp.workflow
|
||||||
|
|
||||||
return openerp.report.interface.report_int._reports[name]
|
if name.startswith('report.'):
|
||||||
|
report = openerp.report.interface.report_int._reports.get(name)
|
||||||
|
if report:
|
||||||
|
return report
|
||||||
|
else:
|
||||||
|
dbname = getattr(threading.currentThread(), 'dbname', None)
|
||||||
|
if dbname:
|
||||||
|
registry = openerp.modules.registry.RegistryManager.get(dbname)
|
||||||
|
with registry.cursor() as cr:
|
||||||
|
return registry['ir.actions.report.xml']._lookup_report(cr, name[len('report.'):])
|
||||||
|
|
||||||
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, _NOTHING, DEFAULT = range(10)
|
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, _NOTHING, DEFAULT = range(10)
|
||||||
#The background is set with 40 plus the number of the color, and the foreground with 30
|
#The background is set with 40 plus the number of the color, and the foreground with 30
|
||||||
|
|
|
@ -5155,6 +5155,15 @@ class BaseModel(object):
|
||||||
get_xml_id = get_external_id
|
get_xml_id = get_external_id
|
||||||
_get_xml_ids = _get_external_ids
|
_get_xml_ids = _get_external_ids
|
||||||
|
|
||||||
|
def print_report(self, cr, uid, ids, name, data, context=None):
|
||||||
|
"""
|
||||||
|
Render the report `name` for the given IDs. The report must be defined
|
||||||
|
for this model, not another.
|
||||||
|
"""
|
||||||
|
report = self.pool['ir.actions.report.xml']._lookup_report(cr, name)
|
||||||
|
assert self._name == report.table
|
||||||
|
return report.create(cr, uid, ids, data, context)
|
||||||
|
|
||||||
# Transience
|
# Transience
|
||||||
def is_transient(self):
|
def is_transient(self):
|
||||||
""" Return whether the model is transient.
|
""" Return whether the model is transient.
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
import openerp
|
||||||
|
|
||||||
import interface
|
import interface
|
||||||
import print_xml
|
import print_xml
|
||||||
import print_fnc
|
import print_fnc
|
||||||
|
@ -30,6 +32,13 @@ import report_sxw
|
||||||
|
|
||||||
import printscreen
|
import printscreen
|
||||||
|
|
||||||
|
def render_report(cr, uid, ids, name, data, context=None):
|
||||||
|
"""
|
||||||
|
Helper to call ``ir.actions.report.xml.render_report()``.
|
||||||
|
"""
|
||||||
|
registry = openerp.modules.registry.RegistryManager.get(cr.dbname)
|
||||||
|
return registry['ir.actions.report.xml'].render_report(cr, uid, ids, name, data, context)
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import re
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
import openerp.pooler as pooler
|
import openerp.pooler as pooler
|
||||||
|
|
||||||
|
import openerp
|
||||||
import openerp.tools as tools
|
import openerp.tools as tools
|
||||||
import openerp.modules
|
import openerp.modules
|
||||||
import print_xml
|
import print_xml
|
||||||
|
@ -43,11 +44,16 @@ class report_int(object):
|
||||||
|
|
||||||
_reports = {}
|
_reports = {}
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name, register=True):
|
||||||
if not name.startswith('report.'):
|
if register:
|
||||||
raise Exception('ConceptionError, bad report name, should start with "report."')
|
assert openerp.conf.deprecation.allow_report_int_registration
|
||||||
assert name not in self._reports, 'The report "%s" already exists!' % name
|
assert name.startswith('report.'), 'Report names should start with "report.".'
|
||||||
self._reports[name] = self
|
assert name not in self._reports, 'The report "%s" already exists.' % name
|
||||||
|
self._reports[name] = self
|
||||||
|
else:
|
||||||
|
# The report is instanciated at each use site, which is ok.
|
||||||
|
pass
|
||||||
|
|
||||||
self.__name = name
|
self.__name = name
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -65,8 +71,8 @@ class report_rml(report_int):
|
||||||
XML -> DATAS -> RML -> PDF -> HTML
|
XML -> DATAS -> RML -> PDF -> HTML
|
||||||
using a XSL:RML transformation
|
using a XSL:RML transformation
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, table, tmpl, xsl):
|
def __init__(self, name, table, tmpl, xsl, register=True):
|
||||||
super(report_rml, self).__init__(name)
|
super(report_rml, self).__init__(name, register=register)
|
||||||
self.table = table
|
self.table = table
|
||||||
self.internal_header=False
|
self.internal_header=False
|
||||||
self.tmpl = tmpl
|
self.tmpl = tmpl
|
||||||
|
|
|
@ -264,7 +264,7 @@ class document(object):
|
||||||
def parse_tree(self, ids, model, context=None):
|
def parse_tree(self, ids, model, context=None):
|
||||||
if not context:
|
if not context:
|
||||||
context={}
|
context={}
|
||||||
browser = self.pool.get(model).browse(self.cr, self.uid, ids, context)
|
browser = self.pool[model].browse(self.cr, self.uid, ids, context)
|
||||||
self.parse_node(self.dom, self.doc, browser)
|
self.parse_node(self.dom, self.doc, browser)
|
||||||
|
|
||||||
def parse_string(self, xml, ids, model, context=None):
|
def parse_string(self, xml, ids, model, context=None):
|
||||||
|
|
|
@ -388,8 +388,19 @@ class rml_parse(object):
|
||||||
self.setCompany(objects[0].company_id)
|
self.setCompany(objects[0].company_id)
|
||||||
|
|
||||||
class report_sxw(report_rml, preprocess.report):
|
class report_sxw(report_rml, preprocess.report):
|
||||||
def __init__(self, name, table, rml=False, parser=rml_parse, header='external', store=False):
|
"""
|
||||||
report_rml.__init__(self, name, table, rml, '')
|
The register=True kwarg has been added to help remove the
|
||||||
|
openerp.netsvc.LocalService() indirection and the related
|
||||||
|
openerp.report.interface.report_int._reports dictionary:
|
||||||
|
report_sxw registered in XML with auto=False are also registered in Python.
|
||||||
|
In that case, they are registered in the above dictionary. Since
|
||||||
|
registration is automatically done upon instanciation, and that
|
||||||
|
instanciation is needed before rendering, a way was needed to
|
||||||
|
instanciate-without-register a report. In the future, no report
|
||||||
|
should be registered in the above dictionary and it will be dropped.
|
||||||
|
"""
|
||||||
|
def __init__(self, name, table, rml=False, parser=rml_parse, header='external', store=False, register=True):
|
||||||
|
report_rml.__init__(self, name, table, rml, '', register=register)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.parser = parser
|
self.parser = parser
|
||||||
self.header = header
|
self.header = header
|
||||||
|
|
|
@ -5,8 +5,8 @@ import logging
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import openerp.netsvc
|
|
||||||
import openerp.pooler
|
import openerp.pooler
|
||||||
|
import openerp.report
|
||||||
from openerp import tools
|
from openerp import tools
|
||||||
|
|
||||||
import security
|
import security
|
||||||
|
@ -51,8 +51,7 @@ def exp_render_report(db, uid, object, ids, datas=None, context=None):
|
||||||
|
|
||||||
cr = openerp.pooler.get_db(db).cursor()
|
cr = openerp.pooler.get_db(db).cursor()
|
||||||
try:
|
try:
|
||||||
obj = openerp.netsvc.LocalService('report.'+object)
|
result, format = openerp.report.render_report(cr, uid, ids, object, datas, context)
|
||||||
(result, format) = obj.create(cr, uid, ids, datas, context)
|
|
||||||
if not result:
|
if not result:
|
||||||
tb = sys.exc_info()
|
tb = sys.exc_info()
|
||||||
self_reports[id]['exception'] = openerp.exceptions.DeferredException('RML is not available at specified location or not enough data to print!', tb)
|
self_reports[id]['exception'] = openerp.exceptions.DeferredException('RML is not available at specified location or not enough data to print!', tb)
|
||||||
|
@ -90,8 +89,7 @@ def exp_report(db, uid, object, ids, datas=None, context=None):
|
||||||
def go(id, uid, ids, datas, context):
|
def go(id, uid, ids, datas, context):
|
||||||
cr = openerp.pooler.get_db(db).cursor()
|
cr = openerp.pooler.get_db(db).cursor()
|
||||||
try:
|
try:
|
||||||
obj = openerp.netsvc.LocalService('report.'+object)
|
result, format = openerp.report.render_report(cr, uid, ids, object, datas, context)
|
||||||
(result, format) = obj.create(cr, uid, ids, datas, context)
|
|
||||||
if not result:
|
if not result:
|
||||||
tb = sys.exc_info()
|
tb = sys.exc_info()
|
||||||
self_reports[id]['exception'] = openerp.exceptions.DeferredException('RML is not available at specified location or not enough data to print!', tb)
|
self_reports[id]['exception'] = openerp.exceptions.DeferredException('RML is not available at specified location or not enough data to print!', tb)
|
||||||
|
|
|
@ -294,7 +294,8 @@ form: module.record_id""" % (xml_id,)
|
||||||
res[dest] = rec.get(f,'').encode('utf8')
|
res[dest] = rec.get(f,'').encode('utf8')
|
||||||
assert res[dest], "Attribute %s of report is empty !" % (f,)
|
assert res[dest], "Attribute %s of report is empty !" % (f,)
|
||||||
for field,dest in (('rml','report_rml'),('file','report_rml'),('xml','report_xml'),('xsl','report_xsl'),
|
for field,dest in (('rml','report_rml'),('file','report_rml'),('xml','report_xml'),('xsl','report_xsl'),
|
||||||
('attachment','attachment'),('attachment_use','attachment_use'), ('usage','usage')):
|
('attachment','attachment'),('attachment_use','attachment_use'), ('usage','usage'),
|
||||||
|
('report_type', 'report_type'), ('parser', 'parser')):
|
||||||
if rec.get(field):
|
if rec.get(field):
|
||||||
res[dest] = rec.get(field).encode('utf8')
|
res[dest] = rec.get(field).encode('utf8')
|
||||||
if rec.get('auto'):
|
if rec.get('auto'):
|
||||||
|
@ -304,8 +305,6 @@ form: module.record_id""" % (xml_id,)
|
||||||
res['report_sxw_content'] = sxw_content
|
res['report_sxw_content'] = sxw_content
|
||||||
if rec.get('header'):
|
if rec.get('header'):
|
||||||
res['header'] = eval(rec.get('header','False'))
|
res['header'] = eval(rec.get('header','False'))
|
||||||
if rec.get('report_type'):
|
|
||||||
res['report_type'] = rec.get('report_type')
|
|
||||||
|
|
||||||
res['multi'] = rec.get('multi') and eval(rec.get('multi','False'))
|
res['multi'] = rec.get('multi') and eval(rec.get('multi','False'))
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
through the code of yaml tests.
|
through the code of yaml tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import openerp.netsvc as netsvc
|
import openerp.report
|
||||||
import openerp.tools as tools
|
import openerp.tools as tools
|
||||||
import logging
|
import logging
|
||||||
import openerp.pooler as pooler
|
import openerp.pooler as pooler
|
||||||
|
@ -49,8 +49,8 @@ def try_report(cr, uid, rname, ids, data=None, context=None, our_module=None):
|
||||||
rname_s = rname[7:]
|
rname_s = rname[7:]
|
||||||
else:
|
else:
|
||||||
rname_s = rname
|
rname_s = rname
|
||||||
_logger.log(netsvc.logging.TEST, " - Trying %s.create(%r)", rname, ids)
|
_logger.log(logging.TEST, " - Trying %s.create(%r)", rname, ids)
|
||||||
res = netsvc.LocalService(rname).create(cr, uid, ids, data, context)
|
res = openerp.report.render_report(cr, uid, ids, rname_s, data, context)
|
||||||
if not isinstance(res, tuple):
|
if not isinstance(res, tuple):
|
||||||
raise RuntimeError("Result of %s.create() should be a (data,format) tuple, now it is a %s" % \
|
raise RuntimeError("Result of %s.create() should be a (data,format) tuple, now it is a %s" % \
|
||||||
(rname, type(res)))
|
(rname, type(res)))
|
||||||
|
@ -92,7 +92,7 @@ def try_report(cr, uid, rname, ids, data=None, context=None, our_module=None):
|
||||||
_logger.warning("Report %s produced a \"%s\" chunk, cannot examine it", rname, res_format)
|
_logger.warning("Report %s produced a \"%s\" chunk, cannot examine it", rname, res_format)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
_logger.log(netsvc.logging.TEST, " + Report %s produced correctly.", rname)
|
_logger.log(logging.TEST, " + Report %s produced correctly.", rname)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def try_report_action(cr, uid, action_id, active_model=None, active_ids=None,
|
def try_report_action(cr, uid, action_id, active_model=None, active_ids=None,
|
||||||
|
@ -126,7 +126,7 @@ def try_report_action(cr, uid, action_id, active_model=None, active_ids=None,
|
||||||
pool = pooler.get_pool(cr.dbname)
|
pool = pooler.get_pool(cr.dbname)
|
||||||
|
|
||||||
def log_test(msg, *args):
|
def log_test(msg, *args):
|
||||||
_logger.log(netsvc.logging.TEST, " - " + msg, *args)
|
_logger.log(logging.TEST, " - " + msg, *args)
|
||||||
|
|
||||||
datas = {}
|
datas = {}
|
||||||
if active_model:
|
if active_model:
|
||||||
|
|
|
@ -5,6 +5,7 @@ import time # used to eval time.strftime expressions
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import openerp
|
||||||
import openerp.pooler as pooler
|
import openerp.pooler as pooler
|
||||||
import openerp.sql_db as sql_db
|
import openerp.sql_db as sql_db
|
||||||
import misc
|
import misc
|
||||||
|
@ -281,7 +282,6 @@ class YamlInterpreter(object):
|
||||||
return record_dict
|
return record_dict
|
||||||
|
|
||||||
def process_record(self, node):
|
def process_record(self, node):
|
||||||
import openerp.osv as osv
|
|
||||||
record, fields = node.items()[0]
|
record, fields = node.items()[0]
|
||||||
model = self.get_model(record.model)
|
model = self.get_model(record.model)
|
||||||
|
|
||||||
|
@ -543,7 +543,14 @@ class YamlInterpreter(object):
|
||||||
python, statements = node.items()[0]
|
python, statements = node.items()[0]
|
||||||
model = self.get_model(python.model)
|
model = self.get_model(python.model)
|
||||||
statements = statements.replace("\r\n", "\n")
|
statements = statements.replace("\r\n", "\n")
|
||||||
code_context = { 'model': model, 'cr': self.cr, 'uid': self.uid, 'log': self._log, 'context': self.context }
|
code_context = {
|
||||||
|
'model': model,
|
||||||
|
'cr': self.cr,
|
||||||
|
'uid': self.uid,
|
||||||
|
'log': self._log,
|
||||||
|
'context': self.context,
|
||||||
|
'openerp': openerp,
|
||||||
|
}
|
||||||
code_context.update({'self': model}) # remove me when no !python block test uses 'self' anymore
|
code_context.update({'self': model}) # remove me when no !python block test uses 'self' anymore
|
||||||
try:
|
try:
|
||||||
code_obj = compile(statements, self.filename, 'exec')
|
code_obj = compile(statements, self.filename, 'exec')
|
||||||
|
|
Loading…
Reference in New Issue