[FIX] web: Kanban: create several records on slow network

Before this rev., it crashed when the user used the quick create
to create several records (very quickly, or on a slow network),
e.g. on crm.lead (there must be a date field on the kanban record
to reproduce the crash).

The crash occurred when the 'read' RPCs for the created records
return misordered. For instance:
  1) 'name_create' record 1 (called and returned)
  2) call 'read' for record 1
  3) 'name_create' record 2 (called and returned)
  4) call 'read' for record 2
  5) 'read' for record 2 returns
  6) 'read' for record 1 returns

At step 5, the kanban column was updated with the new state, but
this state already contained record 1, which wasn't fetched yet.

This rev. ensures that the created records are added to the state
once they are fetched and ready to be displayed, not before.
This commit is contained in:
Aaron Bohy
2018-01-19 09:57:41 +01:00
parent 66a95d91aa
commit ac0e452890
2 changed files with 83 additions and 7 deletions
@@ -22,6 +22,7 @@ var KanbanModel = BasicModel.extend({
* @returns {Deferred<string>} resolves to the local id of the new record
*/
addRecordToGroup: function (groupID, resId) {
var self = this;
var group = this.localData[groupID];
var new_record = this._makeDataPoint({
res_id: resId,
@@ -31,15 +32,16 @@ var KanbanModel = BasicModel.extend({
viewType: group.viewType,
parentID: groupID,
});
group.data.unshift(new_record.id);
group.res_ids.unshift(resId);
group.count++;
// update the res_ids and count of the parent
this.localData[group.parentID].count++;
this._updateParentResIDs(group);
return this._fetchRecord(new_record).then(function (result) {
group.data.unshift(new_record.id);
group.res_ids.unshift(resId);
group.count++;
// update the res_ids and count of the parent
self.localData[group.parentID].count++;
self._updateParentResIDs(group);
return result.id;
});
},
@@ -546,6 +546,80 @@ QUnit.module('Views', {
kanban.destroy();
});
QUnit.test('quick create several records on slow network', function (assert) {
assert.expect(6);
var self = this;
var def;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
'<field name="bar"/>' +
'<templates><t t-name="kanban-box">' +
'<div><field name="foo"/></div>' +
'</t></templates></kanban>',
groupBy: ['bar'],
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'name_create') {
return result.then(function (result) {
// simulate a dynamic default value for foo based on display_name,
// so that we can check that the record has been fetched before
// being displayed
var newRec = _.findWhere(self.data.partner.records, {id: result[0]});
newRec.foo = newRec.display_name;
return result;
});
}
if (args.method === 'read') {
return $.when(def).then(_.constant(result));
}
return result;
},
});
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
"first column should contain one record");
// click to add a record, and add two in a row (first one will be delayed)
kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1,
"the quick create should be open");
def = $.Deferred();
kanban.$('.o_kanban_quick_create input')
.val('new partner 1')
.trigger($.Event('keypress', {
which: $.ui.keyCode.ENTER,
keyCode: $.ui.keyCode.ENTER,
}));
var firstDef = def;
def = null;
kanban.$('.o_kanban_quick_create input')
.val('new partner 2')
.trigger($.Event('keypress', {
which: $.ui.keyCode.ENTER,
keyCode: $.ui.keyCode.ENTER,
}));
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
"first column should now contain two records");
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record:first').text(),
'new partner 2', "new record should have been fetched");
firstDef.resolve();
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3,
"first column should now contain three records");
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record:first').text(),
'new partner 1', "new record should have been fetched");
kanban.destroy();
});
QUnit.test('quick create fail in grouped', function (assert) {
assert.expect(7);