From 29e4394af96eb4856fad913d2427320c11c30523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Fri, 14 Jul 2017 12:19:20 +0200 Subject: [PATCH] [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. --- .../static/src/js/views/basic/basic_model.js | 19 +++++++ .../src/js/views/form/form_controller.js | 26 ++++----- addons/web/static/tests/views/form_tests.js | 54 ++++++++++++++++--- 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index c562fa388f0..5fb77204ec7 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -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 diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 2b607496e85..fa84f11df7f 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -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 diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 6d212a9f001..fd395892e31 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -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:'
' + + '' + + '
' + + '' + + '
' + + '' + + '' + + '' + + '
' + + '
', + 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(); });