[FIX] web: properly reload record data before doing another action
When a user edit a record, then click on a stat button, the web client was a little too aggressive in avoiding to reload data. It was assuming that even if the server overrides the create method, the web client did not need to know anything about the record before executing the action from the stat button. However, that assumption is incorrect: the display_name property is needed to correctly display the breadcrumbs. For example, here is a scenario that was not correct: open a res.partner in a form view, edit its name, then click on one of the stat button. You will see that the breadcrumb is not properly updated. To fix this issue, we have to reload the record, and to properly update the title property. In this commit, we also add a getName method in the model.
This commit is contained in:
@@ -84,11 +84,14 @@ odoo.define('web.BasicModel', function (require) {
|
||||
|
||||
var AbstractModel = require('web.AbstractModel');
|
||||
var concurrency = require('web.concurrency');
|
||||
var core = require('web.core');
|
||||
var Context = require('web.Context');
|
||||
var Domain = require('web.Domain');
|
||||
var fieldUtils = require('web.field_utils');
|
||||
var session = require('web.session');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
var x2ManyCommands = {
|
||||
// (0, _, {values})
|
||||
CREATE: 0,
|
||||
@@ -420,6 +423,22 @@ var BasicModel = AbstractModel.extend({
|
||||
this._sortList(list);
|
||||
return list;
|
||||
},
|
||||
/**
|
||||
* Returns the current display_name for the record.
|
||||
*
|
||||
* @param {string} id the localID for a valid record element
|
||||
* @returns {string}
|
||||
*/
|
||||
getName: function (id) {
|
||||
var record = this.localData[id];
|
||||
if (record._changes && 'display_name' in record._changes) {
|
||||
return record._changes.display_name;
|
||||
}
|
||||
if ('display_name' in record.data) {
|
||||
return record.data.display_name;
|
||||
}
|
||||
return _t("New");
|
||||
},
|
||||
/**
|
||||
* Returns true if a record is dirty. A record is considered dirty if it has
|
||||
* some unsaved changes, marked by the _isDirty property on the record or
|
||||
|
||||
@@ -87,8 +87,7 @@ var FormController = BasicController.extend({
|
||||
* @returns {string}
|
||||
*/
|
||||
getTitle: function () {
|
||||
var dataPoint = this.model.get(this.handle, {raw: true});
|
||||
return dataPoint.data.display_name || _t('New');
|
||||
return this.model.getName(this.handle);
|
||||
},
|
||||
/**
|
||||
* Called each time the form view is attached into the DOM
|
||||
@@ -183,13 +182,15 @@ var FormController = BasicController.extend({
|
||||
* @override
|
||||
*/
|
||||
saveRecord: function () {
|
||||
var result = this._super.apply(this, arguments);
|
||||
if (_t.database.multi_lang) {
|
||||
var self = this;
|
||||
result.then(function (changedFields) {
|
||||
if (!changedFields.length) {
|
||||
return changedFields;
|
||||
}
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function (changedFields) {
|
||||
// the title could have been changed
|
||||
self.set('title', self.getTitle());
|
||||
self._updateEnv();
|
||||
|
||||
if (_t.database.multi_lang && changedFields.length) {
|
||||
// need to make sure changed fields that should be translated
|
||||
// are displayed with an alert
|
||||
var fields = self.renderer.state.fields;
|
||||
var alertFields = [];
|
||||
for (var k = 0; k < changedFields.length; k++) {
|
||||
@@ -201,9 +202,9 @@ var FormController = BasicController.extend({
|
||||
if (alertFields.length) {
|
||||
self.renderer.displayTranslationAlert(alertFields);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return changedFields;
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -370,7 +371,6 @@ var FormController = BasicController.extend({
|
||||
// save the record but don't switch to readonly mode
|
||||
def = this.saveRecord(this.handle, {
|
||||
stayInEdit: true,
|
||||
reload: false,
|
||||
}).then(function () {
|
||||
// we need to reget the record to make sure we have changes made
|
||||
// by the basic model, such as the new res_id, if the record is
|
||||
|
||||
@@ -920,7 +920,7 @@ QUnit.module('Views', {
|
||||
|
||||
QUnit.test('buttons in form view, new record', function (assert) {
|
||||
// this simulates a situation similar to the settings forms.
|
||||
assert.expect(6);
|
||||
assert.expect(7);
|
||||
|
||||
var resID;
|
||||
|
||||
@@ -960,12 +960,12 @@ QUnit.module('Views', {
|
||||
});
|
||||
form.$('.o_form_statusbar button.p').click();
|
||||
|
||||
assert.verifySteps(['default_get', 'create', 'execute_action', 'read']);
|
||||
assert.verifySteps(['default_get', 'create', 'read', 'execute_action', 'read']);
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('buttons in form view, new record, with field id in view', function (assert) {
|
||||
assert.expect(6);
|
||||
assert.expect(7);
|
||||
// buttons in form view are one of the rare example of situation when we
|
||||
// save a record without reloading it immediately, because we only care
|
||||
// about its id for the next step. But at some point, if the field id
|
||||
@@ -1010,7 +1010,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
form.$('.o_form_statusbar button.p').click();
|
||||
|
||||
assert.verifySteps(['default_get', 'create', 'execute_action', 'read']);
|
||||
assert.verifySteps(['default_get', 'create', 'read', 'execute_action', 'read']);
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
@@ -1521,7 +1521,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
QUnit.test('clicking on stat buttons in edit mode', function (assert) {
|
||||
assert.expect(8);
|
||||
assert.expect(9);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
@@ -1566,7 +1566,49 @@ QUnit.module('Views', {
|
||||
|
||||
assert.strictEqual(form.mode, "edit", "form view should be in edit mode");
|
||||
assert.strictEqual(count, 2, "should have triggered a execute action");
|
||||
assert.verifySteps(['read', 'write']);
|
||||
assert.verifySteps(['read', 'write', 'read']);
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('clicking on stat buttons save and reload in edit mode', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch:'<form string="Partners">' +
|
||||
'<sheet>' +
|
||||
'<div name="button_box">' +
|
||||
'<button class="oe_stat_button" type="action">' +
|
||||
'<field name="int_field" widget="statinfo" string="Some number"/>' +
|
||||
'</button>' +
|
||||
'</div>' +
|
||||
'<group>' +
|
||||
'<field name="name"/>' +
|
||||
'</group>' +
|
||||
'</sheet>' +
|
||||
'</form>',
|
||||
res_id: 2,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'write') {
|
||||
// simulate an override of the model...
|
||||
args.args[1].display_name = "GOLDORAK";
|
||||
args.args[1].name = "GOLDORAK";
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(form.getTitle(), 'second record',
|
||||
"should have correct display_name");
|
||||
form.$buttons.find('.o_form_button_edit').click();
|
||||
form.$('input[name="name"]').val('some other name').trigger('input');
|
||||
|
||||
form.$('.oe_stat_button').first().click();
|
||||
assert.strictEqual(form.getTitle(), 'GOLDORAK',
|
||||
"should have correct display_name");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user