Skip to content
Snippets Groups Projects
Commit be3c89d7 authored by Géry Debongnie's avatar Géry Debongnie
Browse files

[FIX] sale_timesheet: fix crash in project plan

The Project Plan code is quite new, but does some unconventional stuff.
It looks like a form view, but it is actually a client action with a
custom search view.  The problem fixed by this commit is that when we
try to open the project plan from the project kanban view, it crashes.

It was caused by a bad interaction between the dashboard search view and
the action manager.  The dashboard search view trigger a search event,
which bubbles up to the action manager.  Since the project plan is not
loaded yet, the action manager assumed that the search event was for the
kanban view instead of the project plan.

The fix is to prevent the event from bubbling up, since the project
plan already handles the search event anyway.

Note that we also set the title in this commit to a default value, to
make sure that if we reload the client action, its title is set to a
more interesting value than 'Undefined'.

We also added a few tests, which could have prevented this mess.  Now it
should be easy to add more tests whenever needed.
parent 611e62ef
No related branches found
No related tags found
No related merge requests found
odoo.define('project_timesheet.project_plan', function (require) {
odoo.define('sale_timesheet.ProjectPlan', function (require) {
'use strict';
var ajax = require('web.ajax');
......@@ -25,6 +25,7 @@ var PlanAction = Widget.extend(ControlPanelMixin, {
this._super.apply(this, arguments);
this.action = action;
this.action_manager = parent;
this.set('title', action.name || _t('Overview'));
},
willStart: function () {
var self = this;
......@@ -213,6 +214,7 @@ var PlanAction = Widget.extend(ControlPanelMixin, {
});
},
_onSearch: function (search_event) {
search_event.stopPropagation();
var session = this.getSession();
// group by are disabled, so we don't take care of them
var result = pyeval.eval_domains_and_contexts({
......@@ -226,4 +228,5 @@ var PlanAction = Widget.extend(ControlPanelMixin, {
core.action_registry.add('timesheet.plan', PlanAction);
return PlanAction;
});
odoo.define('sale_timesheet.timesheet_plan_tests', function (require) {
"use strict";
var ProjectPlan = require('sale_timesheet.ProjectPlan');
var testUtils = require('web.test_utils');
var Widget = require('web.Widget');
function createPlan(params) {
var Parent = Widget.extend({
do_push_state: function () {},
});
var parent = new Parent();
testUtils.addMockEnvironment(parent, params);
var plan = new ProjectPlan(parent, params.action);
var selector = params.debug ? 'body' : '#qunit-fixture';
plan.appendTo($(selector));
plan.destroy = function () {
delete plan.destroy;
parent.destroy();
};
return plan;
}
QUnit.module('Timesheet Plan', {
beforeEach: function () {
this.data = {
'account.analytic.line': {
fields: {
account_id: {string: "Analytic account", type: "many2one", relation: "account.analytic.account"},
},
records: []
},
};
}
}, function () {
QUnit.test('basic timesheet plan rendering', function (assert) {
assert.expect(5);
var plan = createPlan({
archs: {
'account.analytic.line,false,search': '<search></search>',
},
data: this.data,
action: {},
mockRPC: function (route) {
assert.step(route);
if (route === '/timesheet/plan') {
return $.when({html_content: 'Banach-Tarski'});
}
return this._super.apply(this, arguments);
},
intercepts: {
search: function () {
// when the search event get up to the action manager,
// bad things can happen
throw new Error('Search event should not get out of client action');
},
},
});
assert.verifySteps([
"/web/dataset/call_kw/account.analytic.line",
"/timesheet/plan"
]);
assert.strictEqual(plan.$el.text(), 'Banach-Tarski', 'should have rendered html content');
assert.strictEqual(plan.get('title'), 'Overview',
'default title should be set');
plan.destroy();
});
QUnit.test('timesheet action takes action name into account', function (assert) {
assert.expect(1);
var plan = createPlan({
archs: {
'account.analytic.line,false,search': '<search></search>',
},
data: this.data,
action: {name: 'Fibonacci'},
mockRPC: function (route) {
if (route === '/timesheet/plan') {
return $.when({html_content: 'Banach-Tarski'});
}
return this._super.apply(this, arguments);
},
});
assert.strictEqual(plan.get('title'), 'Fibonacci',
'title should be set from the action name');
plan.destroy();
});
});
});
......@@ -8,6 +8,14 @@
</xpath>
</template>
<template id="qunit_suite" name="timesheet plan tests" inherit_id="web.qunit_suite">
<xpath expr="//script[contains(@src, '/web/static/tests/views/kanban_tests.js')]" position="after">
<script type="text/javascript" src="/sale_timesheet/static/tests/timesheet_plan_tests.js"></script>
</xpath>
</template>
<template id="timesheet_plan" name="Timesheet Plan">
<div class="o_form_view o_form_readonly o_project_plan">
<div class="o_form_sheet_bg">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment