[MIG] report_webkit: migrated to new API
This commit is contained in:
committed by
Yannick Tivisse
parent
803a7e75d4
commit
bc3d12c619
@@ -5,5 +5,5 @@
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
|
||||
import models
|
||||
import wizard
|
||||
import report
|
||||
import wizard
|
||||
|
||||
@@ -54,20 +54,23 @@ TODO:
|
||||
* Web client WYSIWYG
|
||||
""",
|
||||
'version': '0.9',
|
||||
'depends': ['base','report'],
|
||||
'depends': ['base', 'report'],
|
||||
'author': 'Camptocamp',
|
||||
'category': 'Hidden', # i.e a technical module, not shown in Application install menu
|
||||
'category': 'Hidden', # i.e a technical module, not shown in Application install menu
|
||||
'url': 'http://http://www.camptocamp.com/',
|
||||
'data': [ 'security/ir.model.access.csv',
|
||||
'data/report_webkit_data.xml',
|
||||
'wizard/report_webkit_actions_views.xml',
|
||||
'views/company_views.xml',
|
||||
'views/header_views.xml',
|
||||
'views/ir_report_views.xml',
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/report_webkit_data.xml',
|
||||
'wizard/report_webkit_actions_views.xml',
|
||||
'views/company_views.xml',
|
||||
'views/header_views.xml',
|
||||
'views/ir_report_views.xml',
|
||||
],
|
||||
'demo': [
|
||||
"report/webkit_report_demo.xml",
|
||||
],
|
||||
'installable': True,
|
||||
'test': [
|
||||
"test/print.yml",
|
||||
],
|
||||
'auto_install': False,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="ir_property_webkitheaderdefault0" model="ir.property">
|
||||
<field name="fields_id" ref="field_ir_act_report_xml_webkit_header"/>
|
||||
@@ -224,4 +224,4 @@ Np8UjYSiEUGffBy+cgqhd32Fqr3wmkjhO4n+2EpRtPCK8j8CgILN0JP4oAAAAABJRU5ErkJggg==
|
||||
<field eval=""""camptocamp_logo"""" name="name"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -4,25 +4,13 @@
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from odoo import fields, models
|
||||
|
||||
class res_company(osv.osv):
|
||||
|
||||
class ResCompany(models.Model):
|
||||
"""Override company to add Header object link a company can have many header and logos"""
|
||||
|
||||
_inherit = "res.company"
|
||||
_columns = {
|
||||
'header_image' : fields.many2many(
|
||||
'ir.header_img',
|
||||
'company_img_rel',
|
||||
'company_id',
|
||||
'img_id',
|
||||
'Available Images',
|
||||
),
|
||||
'header_webkit' : fields.many2many(
|
||||
'ir.header_webkit',
|
||||
'company_html_rel',
|
||||
'company_id',
|
||||
'html_id',
|
||||
'Available html',
|
||||
),
|
||||
}
|
||||
|
||||
header_image = fields.Many2many('ir.header_img', 'company_img_rel', 'company_id', 'img_id', 'Available Images')
|
||||
header_webkit = fields.Many2many('ir.header_webkit', 'company_html_rel', 'company_id', 'html_id', 'Available html')
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
|
||||
from openerp.tools import convert
|
||||
from odoo.tools import convert
|
||||
|
||||
original_xml_import = convert.xml_import
|
||||
|
||||
@@ -25,8 +25,7 @@ class WebkitXMLImport(original_xml_import):
|
||||
webkit_header_id = False
|
||||
else:
|
||||
webkit_header_id = self.id_get(cr, header)
|
||||
self.pool.get('ir.actions.report.xml').write(cr, self.uid,
|
||||
report_id, {'webkit_header': webkit_header_id})
|
||||
self.env['ir.actions.report.xml'].write(report_id, {'webkit_header': webkit_header_id})
|
||||
return report_id
|
||||
|
||||
convert.xml_import = WebkitXMLImport
|
||||
|
||||
@@ -4,71 +4,66 @@
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from odoo import fields, models
|
||||
|
||||
class HeaderHTML(osv.osv):
|
||||
|
||||
class HeaderHTML(models.Model):
|
||||
"""HTML Header allows you to define HTML CSS and Page format"""
|
||||
|
||||
_name = "ir.header_webkit"
|
||||
_columns = {
|
||||
'company_id' : fields.many2one('res.company', 'Company'),
|
||||
'html' : fields.text('webkit header', help="Set Webkit Report Header"),
|
||||
'footer_html' : fields.text('webkit footer', help="Set Webkit Report Footer."),
|
||||
'css' : fields.text('Header CSS'),
|
||||
'name' : fields.char('Name', required=True),
|
||||
'margin_top' : fields.float('Top Margin (mm)'),
|
||||
'margin_bottom' : fields.float('Bottom Margin (mm)'),
|
||||
'margin_left' : fields.float('Left Margin (mm)'),
|
||||
'margin_right' : fields.float('Right Margin (mm)'),
|
||||
'orientation' : fields.selection(
|
||||
[('Landscape','Landscape'),('Portrait', 'Portrait')],
|
||||
'Orientation',
|
||||
),
|
||||
'format': fields.selection(
|
||||
[
|
||||
('A0' ,'A0 5 841 x 1189 mm'),
|
||||
('A1' ,'A1 6 594 x 841 mm'),
|
||||
('A2' ,'A2 7 420 x 594 mm'),
|
||||
('A3' ,'A3 8 297 x 420 mm'),
|
||||
('A4' ,'A4 0 210 x 297 mm, 8.26 x 11.69 inches'),
|
||||
('A5' ,'A5 9 148 x 210 mm'),
|
||||
('A6' ,'A6 10 105 x 148 mm'),
|
||||
('A7' ,'A7 11 74 x 105 mm'),
|
||||
('A8' ,'A8 12 52 x 74 mm'),
|
||||
('A9' ,'A9 13 37 x 52 mm'),
|
||||
('B0' ,'B0 14 1000 x 1414 mm'),
|
||||
('B1' ,'B1 15 707 x 1000 mm'),
|
||||
('B2' ,'B2 17 500 x 707 mm'),
|
||||
('B3' ,'B3 18 353 x 500 mm'),
|
||||
('B4' ,'B4 19 250 x 353 mm'),
|
||||
('B5' ,'B5 1 176 x 250 mm, 6.93 x 9.84 inches'),
|
||||
('B6' ,'B6 20 125 x 176 mm'),
|
||||
('B7' ,'B7 21 88 x 125 mm'),
|
||||
('B8' ,'B8 22 62 x 88 mm'),
|
||||
('B9' ,'B9 23 33 x 62 mm'),
|
||||
('B10',':B10 16 31 x 44 mm'),
|
||||
('C5E','C5E 24 163 x 229 mm'),
|
||||
('Comm10E','Comm10E 25 105 x 241 mm, U.S. Common 10 Envelope'),
|
||||
('DLE', 'DLE 26 110 x 220 mm'),
|
||||
('Executive','Executive 4 7.5 x 10 inches, 190.5 x 254 mm'),
|
||||
('Folio','Folio 27 210 x 330 mm'),
|
||||
('Ledger', 'Ledger 28 431.8 x 279.4 mm'),
|
||||
('Legal', 'Legal 3 8.5 x 14 inches, 215.9 x 355.6 mm'),
|
||||
('Letter','Letter 2 8.5 x 11 inches, 215.9 x 279.4 mm'),
|
||||
('Tabloid', 'Tabloid 29 279.4 x 431.8 mm'),
|
||||
],
|
||||
'Paper size',
|
||||
required=True,
|
||||
help="Select Proper Paper size"
|
||||
)
|
||||
}
|
||||
|
||||
class HeaderImage(osv.osv):
|
||||
company_id = fields.Many2one('res.company', string='Company')
|
||||
html = fields.Text(string='webkit header', help="Set Webkit Report Header")
|
||||
footer_html = fields.Text(string='webkit footer', help="Set Webkit Report Footer.")
|
||||
css = fields.Text(string='Header CSS')
|
||||
name = fields.Char(required=True)
|
||||
margin_top = fields.Float(string='Top Margin (mm)')
|
||||
margin_bottom = fields.Float(string='Bottom Margin (mm)')
|
||||
margin_left = fields.Float(string='Left Margin (mm)')
|
||||
margin_right = fields.Float(string='Right Margin (mm)')
|
||||
orientation = fields.Selection([
|
||||
('Landscape', 'Landscape'),
|
||||
('Portrait', 'Portrait')
|
||||
], string='Orientation')
|
||||
format = fields.Selection([
|
||||
('A0', 'A0 5 841 x 1189 mm'),
|
||||
('A1', 'A1 6 594 x 841 mm'),
|
||||
('A2', 'A2 7 420 x 594 mm'),
|
||||
('A3', 'A3 8 297 x 420 mm'),
|
||||
('A4', 'A4 0 210 x 297 mm, 8.26 x 11.69 inches'),
|
||||
('A5', 'A5 9 148 x 210 mm'),
|
||||
('A6', 'A6 10 105 x 148 mm'),
|
||||
('A7', 'A7 11 74 x 105 mm'),
|
||||
('A8', 'A8 12 52 x 74 mm'),
|
||||
('A9', 'A9 13 37 x 52 mm'),
|
||||
('B0', 'B0 14 1000 x 1414 mm'),
|
||||
('B1', 'B1 15 707 x 1000 mm'),
|
||||
('B2', 'B2 17 500 x 707 mm'),
|
||||
('B3', 'B3 18 353 x 500 mm'),
|
||||
('B4', 'B4 19 250 x 353 mm'),
|
||||
('B5', 'B5 1 176 x 250 mm, 6.93 x 9.84 inches'),
|
||||
('B6', 'B6 20 125 x 176 mm'),
|
||||
('B7', 'B7 21 88 x 125 mm'),
|
||||
('B8', 'B8 22 62 x 88 mm'),
|
||||
('B9', 'B9 23 33 x 62 mm'),
|
||||
('B10', 'B10 16 31 x 44 mm'),
|
||||
('C5E', 'C5E 24 163 x 229 mm'),
|
||||
('Comm10E', 'Comm10E 25 105 x 241 mm, U.S. Common 10 Envelope'),
|
||||
('DLE', 'DLE 26 110 x 220 mm'),
|
||||
('Executive', 'Executive 4 7.5 x 10 inches, 190.5 x 254 mm'),
|
||||
('Folio', 'Folio 27 210 x 330 mm'),
|
||||
('Ledger', 'Ledger 28 431.8 x 279.4 mm'),
|
||||
('Legal', 'Legal 3 8.5 x 14 inches, 215.9 x 355.6 mm'),
|
||||
('Letter', 'Letter 2 8.5 x 11 inches, 215.9 x 279.4 mm'),
|
||||
('Tabloid', 'Tabloid 29 279.4 x 431.8 mm'),
|
||||
], string='Paper size', required=True, help="Select Proper Paper size")
|
||||
|
||||
|
||||
class HeaderImage(models.Model):
|
||||
"""Logo allows you to define multiple logo per company"""
|
||||
_name = "ir.header_img"
|
||||
_columns = {
|
||||
'company_id' : fields.many2one('res.company', 'Company'),
|
||||
'img' : fields.binary('Image', attachment=True),
|
||||
'name' : fields.char('Name', required =True, help="Name of Image"),
|
||||
'type' : fields.char('Type', required =True, help="Image type(png,gif,jpeg)")
|
||||
}
|
||||
|
||||
company_id = fields.Many2one('res.company', string='Company')
|
||||
img = fields.Binary(string='Image', attachment=True)
|
||||
name = fields.Char(required=True, help="Name of Image")
|
||||
type = fields.Char(required=True, help="Image type(png,gif,jpeg)")
|
||||
|
||||
@@ -4,28 +4,24 @@
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
|
||||
import openerp
|
||||
from openerp.osv import fields, orm
|
||||
import odoo
|
||||
from odoo import api, fields, models
|
||||
|
||||
from webkit_report import WebKitParser
|
||||
|
||||
class ir_actions_report_xml(orm.Model):
|
||||
_inherit = 'ir.actions.report.xml'
|
||||
_columns = {
|
||||
'webkit_header': fields.property(
|
||||
type='many2one', relation='ir.header_webkit',
|
||||
string='Webkit Header', help="The header linked to the report",
|
||||
required=True),
|
||||
'webkit_debug': fields.boolean('Webkit debug',
|
||||
help="Enable the webkit engine debugger"),
|
||||
'report_webkit_data': fields.text('Webkit Template',
|
||||
help="This template will be used if the main report file is not found"),
|
||||
'precise_mode': fields.boolean('Precise Mode',
|
||||
help="This mode allow more precise element position as each object"
|
||||
" is printed on a separate HTML but memory and disk usage are wider.")
|
||||
}
|
||||
|
||||
def _lookup_report(self, cr, name):
|
||||
class IrActionsReportXml(models.Model):
|
||||
_inherit = 'ir.actions.report.xml'
|
||||
|
||||
webkit_header = fields.Many2one('ir.header_webkit', string='Webkit Header', required=True, company_dependent=True,
|
||||
help="The header linked to the report")
|
||||
webkit_debug = fields.Boolean(string='Webkit debug', help="Enable the webkit engine debugger")
|
||||
report_webkit_data = fields.Text(string='Webkit Template', help="This template will be used if the main report file is not found")
|
||||
precise_mode = fields.Boolean(string='Precise Mode', help="This mode allow more precise element position as each object"
|
||||
" is printed on a separate HTML but memory and disk usage are wider.")
|
||||
|
||||
@api.model_cr
|
||||
def _lookup_report(self, name):
|
||||
"""
|
||||
Look up a report definition.
|
||||
"""
|
||||
@@ -36,22 +32,22 @@ class ir_actions_report_xml(orm.Model):
|
||||
# First lookup in the deprecated place, because if the report definition
|
||||
# has not been updated, it is more likely the correct definition is there.
|
||||
# Only reports with custom parser specified in Python are still there.
|
||||
if 'report.' + name in openerp.report.interface.report_int._reports:
|
||||
new_report = openerp.report.interface.report_int._reports['report.' + name]
|
||||
if 'report.' + name in odoo.report.interface.report_int._reports:
|
||||
new_report = odoo.report.interface.report_int._reports['report.' + name]
|
||||
if not isinstance(new_report, WebKitParser):
|
||||
new_report = None
|
||||
else:
|
||||
cr.execute("SELECT * FROM ir_act_report_xml WHERE report_name=%s and report_type=%s", (name, 'webkit'))
|
||||
r = cr.dictfetchone()
|
||||
self.env.cr.execute("SELECT * FROM ir_act_report_xml WHERE report_name=%s and report_type=%s", (name, 'webkit'))
|
||||
r = self.env.cr.dictfetchone()
|
||||
if r:
|
||||
if r['parser']:
|
||||
parser = operator.attrgetter(r['parser'])(openerp.addons)
|
||||
kwargs = { 'parser': parser }
|
||||
parser = operator.attrgetter(r['parser'])(odoo.addons)
|
||||
kwargs = {'parser': parser}
|
||||
else:
|
||||
kwargs = {}
|
||||
|
||||
new_report = WebKitParser('report.'+r['report_name'],
|
||||
r['model'], opj('addons',r['report_rml'] or '/'),
|
||||
new_report = WebKitParser('report.' + r['report_name'],
|
||||
r['model'], opj('addons', r['report_rml'] or '/'),
|
||||
header=r['header'], register=False, **kwargs)
|
||||
else:
|
||||
new_report = None
|
||||
@@ -59,4 +55,4 @@ class ir_actions_report_xml(orm.Model):
|
||||
if new_report:
|
||||
return new_report
|
||||
else:
|
||||
return super(ir_actions_report_xml, self)._lookup_report(cr, name)
|
||||
return super(IrActionsReportXml, self)._lookup_report(name)
|
||||
|
||||
@@ -4,62 +4,50 @@
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
|
||||
import openerp
|
||||
from odoo import api, SUPERUSER_ID
|
||||
|
||||
class WebKitHelper(object):
|
||||
"""Set of usefull report helper"""
|
||||
def __init__(self, cursor, uid, report_id, context):
|
||||
def __init__(self, cr, uid, report_id, context):
|
||||
"constructor"
|
||||
self.cursor = cursor
|
||||
self.cursor = cr
|
||||
self.uid = uid
|
||||
self.pool = openerp.registry(self.cursor.dbname)
|
||||
self.env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
self.report_id = report_id
|
||||
self.context = context
|
||||
|
||||
def embed_image(self, type, img, width=0, height=0) :
|
||||
|
||||
def embed_image(self, type, img, width=0, height=0):
|
||||
"Transform a DB image into an embedded HTML image"
|
||||
|
||||
if width :
|
||||
width = 'width="%spx"'%(width)
|
||||
else :
|
||||
if width:
|
||||
width = 'width="%spx"' % (width)
|
||||
else:
|
||||
width = ' '
|
||||
if height :
|
||||
height = 'height="%spx"'%(height)
|
||||
else :
|
||||
if height:
|
||||
height = 'height="%spx"' % (height)
|
||||
else:
|
||||
height = ' '
|
||||
toreturn = '<img %s %s src="data:image/%s;base64,%s" />'%(
|
||||
width,
|
||||
height,
|
||||
type,
|
||||
str(img))
|
||||
toreturn = '<img %s %s src="data:image/%s;base64,%s" />' % (width, height, type, str(img))
|
||||
return toreturn
|
||||
|
||||
|
||||
|
||||
def get_logo_by_name(self, name):
|
||||
"""Return logo by name"""
|
||||
header_obj = self.pool.get('ir.header_img')
|
||||
header_img_id = header_obj.search(
|
||||
self.cursor,
|
||||
self.uid,
|
||||
[('name','=',name)]
|
||||
)
|
||||
if not header_img_id :
|
||||
header_obj = self.env['ir.header_img']
|
||||
header_img_id = header_obj.search([('name', '=', name)])
|
||||
if not header_img_id:
|
||||
return u''
|
||||
if isinstance(header_img_id, list):
|
||||
header_img_id = header_img_id[0]
|
||||
|
||||
head = header_obj.browse(self.cursor, self.uid, header_img_id)
|
||||
return (head.img, head.type)
|
||||
|
||||
|
||||
def embed_logo_by_name(self, name, width=0, height=0):
|
||||
"""Return HTML embedded logo by name"""
|
||||
img, type = self.get_logo_by_name(name)
|
||||
return self.embed_image(type, img, width, height)
|
||||
|
||||
def embed_company_logo(self, width=0, height=0):
|
||||
cr, uid, context = self.cursor, self.uid, self.context
|
||||
my_user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
my_user = self.env.user
|
||||
logo = my_user.company_id.logo_web
|
||||
return self.embed_image("png", logo, width, height)
|
||||
|
||||
|
||||
|
||||
@@ -2,27 +2,23 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
# Contributor(s) : Florent Xicluna (Wingo SA)
|
||||
# Author: Nicolas Bessi (Camptocamp)
|
||||
# Contributor(s): Florent Xicluna (Wingo SA)
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
from openerp import report
|
||||
import tempfile
|
||||
import time
|
||||
import logging
|
||||
from functools import partial
|
||||
|
||||
from report_helper import WebKitHelper
|
||||
import openerp
|
||||
from openerp.modules.module import get_module_resource
|
||||
from openerp.report.report_sxw import *
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import tools
|
||||
from openerp.tools.translate import _
|
||||
from urllib import urlencode, quote as quote
|
||||
from openerp.exceptions import UserError
|
||||
from odoo import api, tools, SUPERUSER_ID, _
|
||||
from odoo.modules.module import get_module_resource
|
||||
from odoo.report.report_sxw import *
|
||||
from urllib import urlencode, quote
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
from odoo.addons.report_webkit.models.report_helper import WebKitHelper
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -73,12 +69,12 @@ def webkit_report_extender(report_name):
|
||||
|
||||
The given function will be called at the creation of the report. The following arguments
|
||||
will be passed to it (in this order):
|
||||
- pool The model pool.
|
||||
- env The model env.
|
||||
- cr The cursor.
|
||||
- uid The user id.
|
||||
- localcontext The context given to the template engine to render the templates for the
|
||||
current report. This is the context that should be modified.
|
||||
- context The OpenERP context.
|
||||
- context The Odoo context.
|
||||
"""
|
||||
def fct1(fct):
|
||||
lst = _extender_functions.get(report_name)
|
||||
@@ -92,18 +88,16 @@ def webkit_report_extender(report_name):
|
||||
|
||||
class WebKitParser(report_sxw):
|
||||
"""Custom class that use webkit to render HTML reports
|
||||
Code partially taken from report openoffice. Thanks guys :)
|
||||
Code partially taken from report openoffice. Thanks guys:)
|
||||
"""
|
||||
def __init__(self, name, table, rml=False, parser=rml_parse,
|
||||
header=True, store=False, register=True):
|
||||
def __init__(self, name, table, rml=False, parser=rml_parse, header=True, store=False, register=True):
|
||||
self.localcontext = {}
|
||||
report_sxw.__init__(self, name, table, rml, parser,
|
||||
header, store, register=register)
|
||||
report_sxw.__init__(self, name, table, rml, parser, header, store, register=register)
|
||||
|
||||
def get_lib(self, cursor, uid):
|
||||
def get_lib(self, cr, uid):
|
||||
"""Return the lib wkhtml path"""
|
||||
proxy = self.pool['ir.config_parameter']
|
||||
webkit_path = proxy.get_param(cursor, SUPERUSER_ID, 'webkit_path')
|
||||
proxy = self.env['ir.config_parameter'].sudo()
|
||||
webkit_path = proxy.get_param('webkit_path')
|
||||
|
||||
if not webkit_path:
|
||||
try:
|
||||
@@ -120,18 +114,17 @@ class WebKitParser(report_sxw):
|
||||
return webkit_path
|
||||
|
||||
raise UserError(_('Wkhtmltopdf library path is not set') + ' ' +
|
||||
_('Please install executable on your system'
|
||||
' (sudo apt-get install wkhtmltopdf) or download it from here:'
|
||||
' http://code.google.com/p/wkhtmltopdf/downloads/list and set the'
|
||||
' path in the ir.config_parameter with the webkit_path key.'
|
||||
'Minimal version is 0.9.9'))
|
||||
_('Please install executable on your system'
|
||||
' (sudo apt-get install wkhtmltopdf) or download it from here:'
|
||||
' http://code.google.com/p/wkhtmltopdf/downloads/list and set the'
|
||||
' path in the ir.config_parameter with the webkit_path key.'
|
||||
'Minimal version is 0.9.9'))
|
||||
|
||||
def generate_pdf(self, comm_path, report_xml, header, footer, html_list, webkit_header=False):
|
||||
"""Call webkit in order to generate pdf"""
|
||||
if not webkit_header:
|
||||
webkit_header = report_xml.webkit_header
|
||||
fd, out_filename = tempfile.mkstemp(suffix=".pdf",
|
||||
prefix="webkit.tmp.")
|
||||
fd, out_filename = tempfile.mkstemp(suffix=".pdf", prefix="webkit.tmp.")
|
||||
file_to_del = [out_filename]
|
||||
if comm_path:
|
||||
command = [comm_path]
|
||||
@@ -141,35 +134,32 @@ class WebKitParser(report_sxw):
|
||||
command.append('--quiet')
|
||||
# default to UTF-8 encoding. Use <meta charset="latin-1"> to override.
|
||||
command.extend(['--encoding', 'utf-8'])
|
||||
if header :
|
||||
with tempfile.NamedTemporaryFile(suffix=".head.html",
|
||||
delete=False) as head_file:
|
||||
if header:
|
||||
with tempfile.NamedTemporaryFile(suffix=".head.html", delete=False) as head_file:
|
||||
head_file.write(self._sanitize_html(header.encode('utf-8')))
|
||||
file_to_del.append(head_file.name)
|
||||
command.extend(['--header-html', head_file.name])
|
||||
if footer :
|
||||
with tempfile.NamedTemporaryFile(suffix=".foot.html",
|
||||
delete=False) as foot_file:
|
||||
if footer:
|
||||
with tempfile.NamedTemporaryFile(suffix=".foot.html", delete=False) as foot_file:
|
||||
foot_file.write(self._sanitize_html(footer.encode('utf-8')))
|
||||
file_to_del.append(foot_file.name)
|
||||
command.extend(['--footer-html', foot_file.name])
|
||||
|
||||
if webkit_header.margin_top :
|
||||
if webkit_header.margin_top:
|
||||
command.extend(['--margin-top', str(webkit_header.margin_top).replace(',', '.')])
|
||||
if webkit_header.margin_bottom :
|
||||
if webkit_header.margin_bottom:
|
||||
command.extend(['--margin-bottom', str(webkit_header.margin_bottom).replace(',', '.')])
|
||||
if webkit_header.margin_left :
|
||||
if webkit_header.margin_left:
|
||||
command.extend(['--margin-left', str(webkit_header.margin_left).replace(',', '.')])
|
||||
if webkit_header.margin_right :
|
||||
if webkit_header.margin_right:
|
||||
command.extend(['--margin-right', str(webkit_header.margin_right).replace(',', '.')])
|
||||
if webkit_header.orientation :
|
||||
if webkit_header.orientation:
|
||||
command.extend(['--orientation', str(webkit_header.orientation).replace(',', '.')])
|
||||
if webkit_header.format :
|
||||
if webkit_header.format:
|
||||
command.extend(['--page-size', str(webkit_header.format).replace(',', '.')])
|
||||
count = 0
|
||||
for html in html_list :
|
||||
with tempfile.NamedTemporaryFile(suffix="%d.body.html" %count,
|
||||
delete=False) as html_file:
|
||||
for html in html_list:
|
||||
with tempfile.NamedTemporaryFile(suffix="%d.body.html" % count, delete=False) as html_file:
|
||||
count += 1
|
||||
html_file.write(self._sanitize_html(html.encode('utf-8')))
|
||||
file_to_del.append(html_file.name)
|
||||
@@ -179,8 +169,8 @@ class WebKitParser(report_sxw):
|
||||
file_to_del.append(stderr_path)
|
||||
try:
|
||||
status = subprocess.call(command, stderr=stderr_fd)
|
||||
os.close(stderr_fd) # ensure flush before reading
|
||||
stderr_fd = None # avoid closing again in finally block
|
||||
os.close(stderr_fd) # ensure flush before reading
|
||||
stderr_fd = None # avoid closing again in finally block
|
||||
fobj = open(stderr_path, 'r')
|
||||
error_message = fobj.read()
|
||||
fobj.close()
|
||||
@@ -188,7 +178,7 @@ class WebKitParser(report_sxw):
|
||||
error_message = _('No diagnosis message was provided')
|
||||
else:
|
||||
error_message = _('The following diagnosis message was provided:\n') + error_message
|
||||
if status :
|
||||
if status:
|
||||
raise UserError(_("The command 'wkhtmltopdf' failed with error code = %s. Message: %s") % (status, error_message))
|
||||
with open(out_filename, 'rb') as pdf_file:
|
||||
pdf = pdf_file.read()
|
||||
@@ -205,88 +195,77 @@ class WebKitParser(report_sxw):
|
||||
|
||||
def translate_call(self, parser_instance, src):
|
||||
"""Translate String."""
|
||||
ir_translation = self.pool['ir.translation']
|
||||
ir_translation = self.env['ir.translation']
|
||||
name = self.tmpl and 'addons/' + self.tmpl or None
|
||||
res = ir_translation._get_source(parser_instance.cr, parser_instance.uid,
|
||||
name, 'report', parser_instance.localcontext.get('lang', 'en_US'), src)
|
||||
res = ir_translation._get_source(name, 'report', parser_instance.localcontext.get('lang', 'en_US'), src)
|
||||
if res == src:
|
||||
# no translation defined, fallback on None (backward compatibility)
|
||||
res = ir_translation._get_source(parser_instance.cr, parser_instance.uid,
|
||||
None, 'report', parser_instance.localcontext.get('lang', 'en_US'), src)
|
||||
if not res :
|
||||
res = ir_translation._get_source(None, 'report', parser_instance.localcontext.get('lang', 'en_US'), src)
|
||||
if not res:
|
||||
return src
|
||||
return res
|
||||
|
||||
# override needed to keep the attachments storing procedure
|
||||
def create_single_pdf(self, cursor, uid, ids, data, report_xml, context=None):
|
||||
def create_single_pdf(self, cr, uid, ids, data, report_xml, context=None):
|
||||
"""generate the PDF"""
|
||||
|
||||
# just try to find an xml id for the report
|
||||
cr = cursor
|
||||
pool = openerp.registry(cr.dbname)
|
||||
found_xml_ids = pool["ir.model.data"].search(cr, uid, [["model", "=", "ir.actions.report.xml"], \
|
||||
["res_id", "=", report_xml.id]], context=context)
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
found_xml_ids = env["ir.model.data"].search([["model", "=", "ir.actions.report.xml"], ["res_id", "=", report_xml.id]])
|
||||
xml_id = None
|
||||
if found_xml_ids:
|
||||
xml_id = pool["ir.model.data"].read(cr, uid, found_xml_ids[0], ["module", "name"])
|
||||
xml_id = "%s.%s" % (xml_id["module"], xml_id["name"])
|
||||
xml_id = "%s.%s" % (found_xml_ids.module, found_xml_ids.name)
|
||||
|
||||
if context is None:
|
||||
context={}
|
||||
htmls = []
|
||||
if report_xml.report_type != 'webkit':
|
||||
return super(WebKitParser,self).create_single_pdf(cursor, uid, ids, data, report_xml, context=context)
|
||||
return super(WebKitParser, self).create_single_pdf(cr, uid, ids, data, report_xml, context=context)
|
||||
|
||||
parser_instance = self.parser(cursor,
|
||||
uid,
|
||||
self.name2,
|
||||
context=context)
|
||||
parser_instance = self.parser(cr, uid, self.name2, context=context)
|
||||
|
||||
self.pool = pool
|
||||
objs = self.getObjects(cursor, uid, ids, context)
|
||||
self.env = env
|
||||
objs = self.getObjects(cr, uid, ids, context)
|
||||
parser_instance.set_context(objs, data, ids, report_xml.report_type)
|
||||
|
||||
template = False
|
||||
template = False
|
||||
|
||||
if report_xml.report_file :
|
||||
if report_xml.report_file:
|
||||
path = get_module_resource(*report_xml.report_file.split('/'))
|
||||
if path and os.path.exists(path) :
|
||||
if path and os.path.exists(path):
|
||||
template = file(path).read()
|
||||
if not template and report_xml.report_webkit_data :
|
||||
template = report_xml.report_webkit_data
|
||||
if not template :
|
||||
if not template and report_xml.report_webkit_data:
|
||||
template = report_xml.report_webkit_data
|
||||
if not template:
|
||||
raise UserError(_('Webkit report template not found!'))
|
||||
header = report_xml.webkit_header.html
|
||||
footer = report_xml.webkit_header.footer_html
|
||||
if not header and report_xml.use_global_header:
|
||||
raise UserError(_('No header defined for this Webkit report!') + " " + _('Please set a header in company settings.'))
|
||||
if not report_xml.use_global_header :
|
||||
if not report_xml.use_global_header:
|
||||
header = ''
|
||||
default_head = get_module_resource('report_webkit', 'default_header.html')
|
||||
with open(default_head,'r') as f:
|
||||
with open(default_head, 'r') as f:
|
||||
header = f.read()
|
||||
css = report_xml.webkit_header.css
|
||||
if not css :
|
||||
if not css:
|
||||
css = ''
|
||||
|
||||
translate_call = partial(self.translate_call, parser_instance)
|
||||
body_mako_tpl = mako_template(template)
|
||||
helper = WebKitHelper(cursor, uid, report_xml.id, context)
|
||||
helper = WebKitHelper(cr, uid, report_xml.id, context)
|
||||
parser_instance.localcontext['helper'] = helper
|
||||
parser_instance.localcontext['css'] = css
|
||||
parser_instance.localcontext['_'] = translate_call
|
||||
|
||||
# apply extender functions
|
||||
additional = {}
|
||||
if xml_id in _extender_functions:
|
||||
for fct in _extender_functions[xml_id]:
|
||||
fct(pool, cr, uid, parser_instance.localcontext, context)
|
||||
fct(env, cr, uid, parser_instance.localcontext, context)
|
||||
|
||||
if report_xml.precise_mode:
|
||||
ctx = dict(parser_instance.localcontext)
|
||||
for obj in parser_instance.localcontext['objects']:
|
||||
ctx['objects'] = [obj]
|
||||
try :
|
||||
try:
|
||||
html = body_mako_tpl.render(dict(ctx))
|
||||
htmls.append(html)
|
||||
except Exception, e:
|
||||
@@ -294,7 +273,7 @@ class WebKitParser(report_sxw):
|
||||
_logger.info(msg, exc_info=True)
|
||||
raise UserError(msg)
|
||||
else:
|
||||
try :
|
||||
try:
|
||||
html = body_mako_tpl.render(dict(parser_instance.localcontext))
|
||||
htmls.append(html)
|
||||
except Exception, e:
|
||||
@@ -302,50 +281,47 @@ class WebKitParser(report_sxw):
|
||||
_logger.info(msg, exc_info=True)
|
||||
raise UserError(msg)
|
||||
head_mako_tpl = mako_template(header)
|
||||
try :
|
||||
try:
|
||||
head = head_mako_tpl.render(dict(parser_instance.localcontext, _debug=False))
|
||||
except Exception, e:
|
||||
raise UserError(tools.ustr(e))
|
||||
foot = False
|
||||
if footer :
|
||||
if footer:
|
||||
foot_mako_tpl = mako_template(footer)
|
||||
try :
|
||||
try:
|
||||
foot = foot_mako_tpl.render(dict(parser_instance.localcontext))
|
||||
except Exception, e:
|
||||
msg = u"%s" % e
|
||||
_logger.info(msg, exc_info=True)
|
||||
raise UserError(msg)
|
||||
if report_xml.webkit_debug :
|
||||
try :
|
||||
if report_xml.webkit_debug:
|
||||
try:
|
||||
deb = head_mako_tpl.render(dict(parser_instance.localcontext, _debug=tools.ustr("\n".join(htmls))))
|
||||
except Exception, e:
|
||||
msg = u"%s" % e
|
||||
_logger.info(msg, exc_info=True)
|
||||
raise UserError(msg)
|
||||
return (deb, 'html')
|
||||
bin = self.get_lib(cursor, uid)
|
||||
bin = self.get_lib(cr, uid)
|
||||
pdf = self.generate_pdf(bin, report_xml, head, foot, htmls)
|
||||
return (pdf, 'pdf')
|
||||
|
||||
def create(self, cursor, uid, ids, data, context=None):
|
||||
def create(self, cr, uid, ids, data, context=None):
|
||||
"""We override the create function in order to handle generator
|
||||
Code taken from report openoffice. Thanks guys :) """
|
||||
pool = openerp.registry(cursor.dbname)
|
||||
ir_obj = pool['ir.actions.report.xml']
|
||||
report_xml_ids = ir_obj.search(cursor, uid,
|
||||
[('report_name', '=', self.name[7:])], context=context)
|
||||
if report_xml_ids:
|
||||
report_xml = ir_obj.browse(cursor, uid, report_xml_ids[0], context=context)
|
||||
else:
|
||||
return super(WebKitParser, self).create(cursor, uid, ids, data, context)
|
||||
Code taken from report openoffice. Thanks guys:) """
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
ir_obj = env['ir.actions.report.xml']
|
||||
report_xml = ir_obj.search([('report_name', '=', self.name[7:])], limit=1)
|
||||
if not report_xml:
|
||||
return super(WebKitParser, self).create(cr, uid, ids, data, context)
|
||||
|
||||
setattr(report_xml, 'use_global_header', self.header if report_xml.header else False)
|
||||
|
||||
if report_xml.report_type != 'webkit':
|
||||
return super(WebKitParser, self).create(cursor, uid, ids, data, context)
|
||||
result = self.create_source_pdf(cursor, uid, ids, data, report_xml, context)
|
||||
return super(WebKitParser, self).create(cr, uid, ids, data, context)
|
||||
result = self.create_source_pdf(cr, uid, ids, data, report_xml, context)
|
||||
if not result:
|
||||
return (False,False)
|
||||
return (False, False)
|
||||
return result
|
||||
|
||||
def _sanitize_html(self, html):
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
|
||||
import webkit_report_demo
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Nicolas Bessi (Camptocamp)
|
||||
|
||||
|
||||
from openerp.addons.report_webkit.models.webkit_report import webkit_report_extender
|
||||
from openerp import SUPERUSER_ID
|
||||
from odoo.addons.report_webkit.models.webkit_report import webkit_report_extender
|
||||
from odoo import SUPERUSER_ID
|
||||
|
||||
@webkit_report_extender("report_webkit.webkit_demo_report")
|
||||
def extend_demo(pool, cr, uid, localcontext, context):
|
||||
admin = pool.get("res.users").browse(cr, uid, SUPERUSER_ID, context)
|
||||
def extend_demo(env, cr, uid, localcontext, context):
|
||||
admin = env["res.users"].browse(SUPERUSER_ID)
|
||||
localcontext.update({
|
||||
"admin_name": admin.name,
|
||||
})
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<odoo>
|
||||
<report string="Report on reports"
|
||||
id="webkit_demo_report"
|
||||
model="ir.actions.report.xml"
|
||||
name="webkit.ir.actions.report.xml"
|
||||
file="report_webkit/report/webkit_report_demo.mako"
|
||||
report_type="webkit"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<openerp>
|
||||
<data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="currency_del_img">
|
||||
<field name="name">res.company.form.inherit</field>
|
||||
<field name="model">res.company</field>
|
||||
@@ -13,6 +13,4 @@
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<openerp>
|
||||
<data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="header_img">
|
||||
<field name="name">res.company.header.img</field>
|
||||
<field name="name">ir.header.img.form</field>
|
||||
<field name="model">ir.header_img</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Header Image">
|
||||
@@ -16,7 +16,7 @@
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="header_webkit">
|
||||
<field name="name">res.company.header.html</field>
|
||||
<field name="name">ir.header.webkit.form</field>
|
||||
<field name="model">ir.header_webkit</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="HTML Header">
|
||||
@@ -59,5 +59,4 @@
|
||||
</record>
|
||||
<menuitem action="action_header_webkit" id="menu_header_webkit" parent="menu_webkit" sequence="14"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<openerp>
|
||||
<data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="act_report_xml_view" model="ir.ui.view">
|
||||
<field name="name">ir.actions.report.xml.inherit</field>
|
||||
<field name="model">ir.actions.report.xml</field>
|
||||
@@ -19,5 +19,4 @@
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -4,111 +4,59 @@
|
||||
# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
|
||||
# Author : Vincent Renaville
|
||||
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv import fields, osv
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
class report_webkit_actions(osv.osv_memory):
|
||||
|
||||
class ReportWebkitActions(models.TransientModel):
|
||||
_name = "report.webkit.actions"
|
||||
_description = "Webkit Actions"
|
||||
_columns = {
|
||||
'print_button':fields.boolean('Add print button', help="Check this to add a Print action for this Report in the sidebar of the corresponding document types"),
|
||||
'open_action':fields.boolean('Open added action', help="Check this to view the newly added internal print action after creating it (technical view) "),
|
||||
}
|
||||
_defaults = {
|
||||
'print_button': lambda *a: True,
|
||||
'open_action': lambda *a: False,
|
||||
}
|
||||
|
||||
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
||||
""" Changes the view dynamically
|
||||
@param self: The object pointer.
|
||||
@param cr: A database cursor
|
||||
@param uid: ID of the user currently logged in
|
||||
@param context: A standard dictionary
|
||||
@return: New arch of view.
|
||||
"""
|
||||
if not context: context = {}
|
||||
res = super(report_webkit_actions, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar,submenu=False)
|
||||
record_id = context and context.get('active_id', False) or False
|
||||
active_model = context.get('active_model')
|
||||
print_button = fields.Boolean('Add print button', default=True, help="Check this to add a Print action for this Report in the sidebar of the corresponding document types")
|
||||
open_action = fields.Boolean('Open added action', help="Check this to view the newly added internal print action after creating it (technical view) ")
|
||||
|
||||
if not record_id or (active_model and active_model != 'ir.actions.report.xml'):
|
||||
@api.model
|
||||
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
|
||||
res = super(ReportWebkitActions, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
|
||||
record_id = self.env.context.get('active_id')
|
||||
active_model = self.env.context.get('active_model')
|
||||
|
||||
if not record_id or (active_model != 'ir.actions.report.xml'):
|
||||
return res
|
||||
|
||||
report = self.pool['ir.actions.report.xml'].browse(
|
||||
cr,
|
||||
uid,
|
||||
context.get('active_id'),
|
||||
context=context
|
||||
)
|
||||
ir_values_obj = self.pool['ir.values']
|
||||
ids = ir_values_obj.search(
|
||||
cr,
|
||||
uid,
|
||||
[('value','=',report.type+','+str(context.get('active_id')))]
|
||||
)
|
||||
|
||||
if ids:
|
||||
report = self.env['ir.actions.report.xml'].browse(record_id)
|
||||
if self.env['ir.values'].search([('value', '=', report.type + ',' + str(record_id))]):
|
||||
res['arch'] = '''<form string="Add Print Buttons">
|
||||
<label string="Report Action already exist for this report."/>
|
||||
</form>
|
||||
'''
|
||||
|
||||
return res
|
||||
|
||||
def do_action(self, cr, uid, ids, context=None):
|
||||
@api.multi
|
||||
def do_action(self):
|
||||
""" This Function Open added Action.
|
||||
@param self: The object pointer.
|
||||
@param cr: A database cursor
|
||||
@param uid: ID of the user currently logged in
|
||||
@param ids: List of report.webkit.actions's ID
|
||||
@param context: A standard dictionary
|
||||
@return: Dictionary of ir.values form.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
report_obj = self.pool['ir.actions.report.xml']
|
||||
for current in self.browse(cr, uid, ids, context=context):
|
||||
report = report_obj.browse(
|
||||
cr,
|
||||
uid,
|
||||
context.get('active_id'),
|
||||
context=context
|
||||
)
|
||||
IrValues = self.env['ir.values']
|
||||
active_id = self.env.context.get('active_id', False)
|
||||
for current in self:
|
||||
report = self.env['ir.actions.report.xml'].browse(active_id)
|
||||
if current.print_button:
|
||||
ir_values_obj = self.pool['ir.values']
|
||||
res = ir_values_obj.set(
|
||||
cr,
|
||||
uid,
|
||||
'action',
|
||||
'client_print_multi',
|
||||
report.report_name,
|
||||
[report.model],
|
||||
'ir.actions.report.xml,%d' % context.get('active_id', False),
|
||||
isobject=True
|
||||
)
|
||||
res = IrValues.set('action', 'client_print_multi', report.report_name, [report.model],
|
||||
'ir.actions.report.xml,%d' % active_id, isobject=True)
|
||||
else:
|
||||
ir_values_obj = self.pool['ir.values']
|
||||
res = ir_values_obj.set(
|
||||
cr,
|
||||
uid,
|
||||
'action',
|
||||
'client_print_multi',
|
||||
report.report_name,
|
||||
[report.model,0],
|
||||
'ir.actions.report.xml,%d' % context.get('active_id', False),
|
||||
isobject=True
|
||||
)
|
||||
res = IrValues.set('action', 'client_print_multi', report.report_name, [report.model, 0],
|
||||
'ir.actions.report.xml,%d' % active_id, isobject=True)
|
||||
if res[0]:
|
||||
if not current.open_action:
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
|
||||
return {
|
||||
'name': _('Client Actions Connections'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_id' : res[0],
|
||||
'res_id': res[0],
|
||||
'res_model': 'ir.values',
|
||||
'view_id': False,
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="view_report_webkit_actions">
|
||||
<field name="name">Report Webkit actions wizard</field>
|
||||
<field name="name">report.webkit.actions.form</field>
|
||||
<field name="model">report.webkit.actions</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Add Print Buttons" col="4">
|
||||
@@ -27,6 +25,4 @@
|
||||
key2="client_print_multi"
|
||||
target="new"
|
||||
id="wizard_ofdo_report_actions"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user