[MIG] report_csv: Backport from 11.0

This commit is contained in:
Laurent Mignon (ACSONE)
2020-07-29 10:41:37 +02:00
parent 29182742a6
commit 6fb8c68ff9
11 changed files with 144 additions and 73 deletions

View File

@@ -41,7 +41,7 @@ A python class ::
A report XML record ::
<report
<report
id="partner_csv"
model="res.partner"
string="Print to CSV"
@@ -70,6 +70,7 @@ Contributors
------------
* Enric Tobella <etobella@creublanca.es>
* Laurent Mignon <laurent.mignon@acsone.eu>
Maintainer
----------

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
@@ -5,19 +6,18 @@
'summary': "Base module to create csv report",
'author': 'Creu Blanca,'
'ACSONE SA/NV,'
'Odoo Community Association (OCA)',
'website': "https://github.com/oca/reporting-engine",
'category': 'Reporting',
'version': '11.0.1.0.0',
'version': '10.0.1.0.0',
'license': 'AGPL-3',
'external_dependencies': {
'python': [
'csv',
],
},
'depends': [
'base', 'web',
'report',
],
'external_dependencies': {
'python': ['unicodecsv']
},
'data': [
'views/webclient_templates.xml',
],

View File

@@ -1,21 +1,29 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2019 Creu Blanca
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
from odoo.addons.web.controllers import main as report
from odoo.http import content_disposition, route, request
from odoo.tools.safe_eval import safe_eval
import json
import time
from werkzeug import url_decode
from odoo.addons.report.controllers import main as report
from odoo.http import route, request
from odoo.tools.safe_eval import safe_eval
from odoo.addons.web.controllers.main import (
_serialize_exception,
content_disposition
)
from odoo.tools import html_escape
class ReportController(report.ReportController):
@route()
def report_routes(self, reportname, docids=None, converter=None, **data):
if converter == 'csv':
report = request.env['ir.actions.report']._get_report_from_name(
report = request.env['report']._get_report_from_name(
reportname)
context = dict(request.env.context)
if docids:
docids = [int(i) for i in docids.split(',')]
if data.get('options'):
@@ -28,6 +36,7 @@ class ReportController(report.ReportController):
if data['context'].get('lang'):
del data['context']['lang']
context.update(data['context'])
csv = report.with_context(context).render_csv(
docids, data=data
)[0]
@@ -58,3 +67,43 @@ class ReportController(report.ReportController):
return super(ReportController, self).report_routes(
reportname, docids, converter, **data
)
@route()
def report_download(self, data, token):
"""This function is used by 'qwebactionmanager.js' in order to trigger
the download of a csv/controller report.
:param data: a javascript array JSON.stringified containg report
internal url ([0]) and type [1]
:returns: Response with a filetoken cookie and an attachment header
"""
requestcontent = json.loads(data)
url, type = requestcontent[0], requestcontent[1]
if type != 'csv':
return super(ReportController, self).report_download(data, token)
try:
reportname = url.split('/report/csv/')[1].split('?')[0]
docids = None
if '/' in reportname:
reportname, docids = reportname.split('/')
if docids:
# Generic report:
response = self.report_routes(
reportname, docids=docids, converter='csv')
else:
# Particular report:
# decoding the args represented in JSON
data = url_decode(url.split('?')[1]).items()
response = self.report_routes(
reportname, converter='csv', **dict(data))
response.set_cookie('fileToken', token)
return response
except Exception, e:
se = _serialize_exception(e)
error = {
'code': 200,
'message': "Odoo Server Error",
'data': se
}
return request.make_response(html_escape(json.dumps(error)))

View File

@@ -1 +1,2 @@
from . import ir_report
from . import report
from . import ir_actions_report_xml

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
@@ -5,8 +6,8 @@ from odoo import api, fields, models, _
from odoo.exceptions import UserError
class ReportAction(models.Model):
_inherit = 'ir.actions.report'
class IrActionsReportXml(models.Model):
_inherit = 'ir.actions.report.xml'
report_type = fields.Selection(selection_add=[("csv", "csv")])
@@ -19,15 +20,3 @@ class ReportAction(models.Model):
return report_model.with_context({
'active_model': self.model
}).create_csv_report(docids, data)
@api.model
def _get_report_from_name(self, report_name):
res = super(ReportAction, self)._get_report_from_name(report_name)
if res:
return res
report_obj = self.env['ir.actions.report']
qwebtypes = ['csv']
conditions = [('report_type', 'in', qwebtypes),
('report_name', '=', report_name)]
context = self.env['res.users'].context_get()
return report_obj.with_context(context).search(conditions, limit=1)

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Akretion (http://www.akretion.com/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models
class Report(models.Model):
_inherit = 'report'
@api.model
def _get_report_from_name(self, report_name):
"""Get the first record of ir.actions.report.xml having the
``report_name`` as value for the field report_name.
"""
res = super(Report, self)._get_report_from_name(report_name)
if res:
return res
report_obj = self.env['ir.actions.report.xml']
qwebtypes = ['csv']
conditions = [('report_type', 'in', qwebtypes),
('report_name', '=', report_name)]
context = self.env['res.users'].context_get()
return report_obj.with_context(context).search(conditions, limit=1)

View File

@@ -1,17 +1,18 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from io import StringIO
import logging
from StringIO import StringIO
from odoo import models
import logging
_logger = logging.getLogger(__name__)
logger = logging.getLogger(__name__)
try:
import csv
import unicodecsv as csv
except ImportError:
_logger.debug('Can not import csvwriter`.')
logger.debug('Cannot import unicodecsv')
class ReportCSVAbstract(models.AbstractModel):

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import csv
@@ -17,7 +18,7 @@ class PartnerCSV(models.AbstractModel):
})
def csv_report_options(self):
res = super().csv_report_options()
res = super(PartnerCSV, self).csv_report_options()
res['fieldnames'].append('name')
res['fieldnames'].append('email')
res['delimiter'] = ';'

View File

@@ -7,41 +7,48 @@ var ActionManager= require('web.ActionManager');
var crash_manager = require('web.crash_manager');
var framework = require('web.framework');
var trigger_download = function(session, response, c, action, options) {
session.get_file({
url: '/report/download',
data: {data: JSON.stringify(response)},
complete: framework.unblockUI,
error: c.rpc_error.bind(c),
success: function(){
if (action && options && !action.dialog) {
options.on_close();
}
},
});
};
ActionManager.include({
ir_actions_report: function (action, options){
ir_actions_report_xml: function(action, options) {
var self = this;
var cloned_action = _.clone(action);
if (cloned_action.report_type === 'csv') {
// Py3o reports
if ('report_type' in action && action.report_type == 'csv' ) {
framework.blockUI();
var report_csv_url = 'report/csv/' + cloned_action.report_name;
if (_.isUndefined(cloned_action.data) ||
_.isNull(cloned_action.data) ||
(_.isObject(cloned_action.data) && _.isEmpty(cloned_action.data)))
{
if(cloned_action.context.active_ids) {
report_csv_url += '/' + cloned_action.context.active_ids.join(',');
action = _.clone(action);
var report_url = '/report/csv/' + action.report_name;;
// generic report: no query string
// particular: query string of action.data.form and context
if (!('data' in action) || !(action.data)) {
if ('active_ids' in action.context) {
report_url += "/" + action.context.active_ids.join(',');
}
} else {
report_csv_url += '?options=' + encodeURIComponent(JSON.stringify(cloned_action.data));
report_csv_url += '&context=' + encodeURIComponent(JSON.stringify(cloned_action.context));
report_url += "&options=" + encodeURIComponent(JSON.stringify(action.data));
report_url += "&context=" + encodeURIComponent(JSON.stringify(action.context));
}
self.getSession().get_file({
url: report_csv_url,
data: {data: JSON.stringify([
report_csv_url,
cloned_action.report_type
])},
error: crash_manager.rpc_error.bind(crash_manager),
success: function (){
if(cloned_action && options && !cloned_action.dialog){
options.on_close();
}
}
});
framework.unblockUI();
return;
var response = new Array();
response[0] = report_url;
response[1] = action.report_type;
var c = crash_manager;
return trigger_download(self.session, response, c, action, options);
} else {
return self._super(action, options);
}
return self._super(action, options);
}
});
});

View File

@@ -1,19 +1,15 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from io import StringIO
import csv
from StringIO import StringIO
from odoo.tests import common
import logging
_logger = logging.getLogger(__name__)
try:
import csv
except ImportError:
_logger.debug('Can not import csv.')
class TestReport(common.TransactionCase):
def setUp(self):
super().setUp()
report_object = self.env['ir.actions.report']
super(TestReport, self,).setUp()
report_object = self.env['report']
self.csv_report = (
self.env['report.report_csv.abstract']
.with_context(active_model='res.partner')
@@ -25,7 +21,7 @@ class TestReport(common.TransactionCase):
def test_report(self):
report = self.report
self.assertEqual(report.report_type, 'csv')
rep = report.render(self.docs.ids, {})
rep = report.render_csv(self.docs.ids, {})
str_io = StringIO(rep[0])
dict_report = list(csv.DictReader(str_io, delimiter=';',
quoting=csv.QUOTE_ALL))

View File

@@ -2,3 +2,4 @@ xlwt
xlsxwriter
py3o.template
py3o.formats
unicodecsv