odoo.define('web.ReportActionManager', function (require) {
"use strict";
/**
* The purpose of this file is to add the support of Odoo actions of type
* 'ir.actions.report' to the ActionManager.
*/
var ActionManager = require('web.ActionManager');
var core = require('web.core');
var framework = require('web.framework');
var session = require('web.session');
var _t = core._t;
var _lt = core._lt;
// Messages that might be shown to the user dependening on the state of wkhtmltopdf
var link = '
wkhtmltopdf.org';
var WKHTMLTOPDF_MESSAGES = {
broken: _lt('Your installation of Wkhtmltopdf seems to be broken. The report will be shown ' +
'in html.') + link,
install: _lt('Unable to find Wkhtmltopdf on this system. The report will be shown in ' +
'html.') + link,
upgrade: _lt('You should upgrade your version of Wkhtmltopdf to at least 0.12.0 in order to ' +
'get a correct display of headers and footers as well as support for ' +
'table-breaking between pages.') + link,
workers: _lt('You need to start Odoo with at least two workers to print a pdf version of ' +
'the reports.'),
};
ActionManager.include({
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* Downloads a PDF report for the given url. It blocks the UI during the
* report generation and download.
*
* @param {string} url
* @returns {Promise} resolved when the report has been downloaded ;
* rejected if something went wrong during the report generation
*/
_downloadReport: function (url) {
var self = this;
framework.blockUI();
return new Promise(function (resolve, reject) {
var type = 'qweb-' + url.split('/')[2];
var blocked = !session.get_file({
url: '/report/download',
data: {
data: JSON.stringify([url, type]),
context: JSON.stringify(session.user_context),
},
success: resolve,
error: (error) => {
self.call('crash_manager', 'rpc_error', error);
reject();
},
complete: framework.unblockUI,
});
if (blocked) {
// AAB: this check should be done in get_file service directly,
// should not be the concern of the caller (and that way, get_file
// could return a promise)
var message = _t('A popup window with your report was blocked. You ' +
'may need to change your browser settings to allow ' +
'popup windows for this page.');
self.do_warn(_t('Warning'), message, true);
}
});
},
/**
* Launch download action of the report
*
* @private
* @param {Object} action the description of the action to execute
* @param {Object} options @see doAction for details
* @returns {Promise} resolved when the action has been executed
*/
_triggerDownload: function (action, options, type){
var self = this;
var reportUrls = this._makeReportUrls(action);
return this._downloadReport(reportUrls[type]).then(function () {
if (action.close_on_report_download) {
var closeAction = { type: 'ir.actions.act_window_close' };
return self.doAction(closeAction, _.pick(options, 'on_close'));
} else {
return options.on_close();
}
});
},
/**
* Executes actions of type 'ir.actions.report'.
*
* @private
* @param {Object} action the description of the action to execute
* @param {Object} options @see doAction for details
* @returns {Promise} resolved when the action has been executed
*/
_executeReportAction: function (action, options) {
var self = this;
if (action.report_type === 'qweb-html') {
return this._executeReportClientAction(action, options);
} else if (action.report_type === 'qweb-pdf') {
// check the state of wkhtmltopdf before proceeding
return this.call('report', 'checkWkhtmltopdf').then(function (state) {
// display a notification according to wkhtmltopdf's state
if (state in WKHTMLTOPDF_MESSAGES) {
self.do_notify(_t('Report'), WKHTMLTOPDF_MESSAGES[state], true);
}
if (state === 'upgrade' || state === 'ok') {
// trigger the download of the PDF report
return self._triggerDownload(action, options, 'pdf');
} else {
// open the report in the client action if generating the PDF is not possible
return self._executeReportClientAction(action, options);
}
});
} else if (action.report_type === 'qweb-text') {
return self._triggerDownload(action, options, 'text');
} else {
console.error("The ActionManager can't handle reports of type " +
action.report_type, action);
return Promise.reject();
}
},
/**
* Executes the report client action, either because the report_type is
* 'qweb-html', or because the PDF can't be generated by wkhtmltopdf (in
* the case of 'qweb-pdf' reports).
*
* @param {Object} action
* @param {Object} options
* @returns {Promise} resolved when the client action has been executed
*/
_executeReportClientAction: function (action, options) {
var urls = this._makeReportUrls(action);
var clientActionOptions = _.extend({}, options, {
context: action.context,
data: action.data,
display_name: action.display_name,
name: action.name,
report_file: action.report_file,
report_name: action.report_name,
report_url: urls.html,
});
return this.doAction('report.client_action', clientActionOptions);
},
/**
* Overrides to handle the 'ir.actions.report' actions.
*
* @override
* @private
*/
_handleAction: function (action, options) {
if (action.type === 'ir.actions.report') {
return this._executeReportAction(action, options);
}
return this._super.apply(this, arguments);
},
/**
* Generates an object containing the report's urls (as value) for every
* qweb-type we support (as key). It's convenient because we may want to use
* another report's type at some point (for example, when `qweb-pdf` is not
* available).
*
* @param {Object} action
* @returns {Object}
*/
_makeReportUrls: function (action) {
var reportUrls = {
html: '/report/html/' + action.report_name,
pdf: '/report/pdf/' + action.report_name,
text: '/report/text/' + action.report_name,
};
// We may have to build a query string with `action.data`. It's the place
// were report's using a wizard to customize the output traditionally put
// their options.
if (_.isUndefined(action.data) || _.isNull(action.data) ||
(_.isObject(action.data) && _.isEmpty(action.data))) {
if (action.context.active_ids) {
var activeIDsPath = '/' + action.context.active_ids.join(',');
reportUrls = _.mapObject(reportUrls, function (value) {
return value += activeIDsPath;
});
}
reportUrls.html += '?context=' + encodeURIComponent(JSON.stringify(session.user_context));
} else {
var serializedOptionsPath = '?options=' + encodeURIComponent(JSON.stringify(action.data));
serializedOptionsPath += '&context=' + encodeURIComponent(JSON.stringify(action.context));
reportUrls = _.mapObject(reportUrls, function (value) {
return value += serializedOptionsPath;
});
}
return reportUrls;
},
});
});