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 crash_manager = require('web.crash_manager');
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 {Deferred} resolved when the report has been downloaded ;
* rejected if something went wrong during the report generation
*/
_downloadReport: function (url) {
framework.blockUI();
var def = $.Deferred();
var blocked = !session.get_file({
url: '/report/download',
data: {
data: JSON.stringify([url, 'qweb-pdf']),
},
success: def.resolve.bind(def),
error: function () {
crash_manager.rpc_error.apply(crash_manager, arguments);
def.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 deferred)
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.');
this.do_warn(_t('Warning'), message, true);
}
return def;
},
/**
* 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 {Deferred} 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
var processedActions = [];
var currentAction = action;
var defs = [];
do {
var reportUrls = self._makeReportUrls(currentAction);
defs.push(self._downloadReport(reportUrls.pdf));
processedActions.push(currentAction);
currentAction = currentAction.next_report_to_generate;
} while (currentAction && !_.contains(processedActions, currentAction));
return $.when.apply($, defs).done(options.on_close);
} else {
// open the report in the client action if generating the PDF is not possible
return self._executeReportClientAction(action, options);
}
});
} else {
console.error("The ActionManager can't handle reports of type " +
action.report_type, action);
return $.Deferred().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 {Deferred} 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,
};
// 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;
});
}
} 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;
},
});
});