From 9d7f9cc38c00efa4e75c9c1efeb5a1a7d4262550 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Tue, 24 Oct 2017 17:26:48 +0200 Subject: [PATCH] [FIX] calendar: don't display the created or updated record If the user change a filtered field, the record is not always displayed. Wrong domain construction. The automatic filter must be use to filter and remove items from the view for the unselected and not display the selected. --- .../js/views/calendar/calendar_controller.js | 6 +- .../src/js/views/calendar/calendar_model.js | 21 +- .../web/static/tests/views/calendar_tests.js | 306 +++++++++++++++++- 3 files changed, 321 insertions(+), 12 deletions(-) diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js index 11390793c68..d46cb1c5241 100644 --- a/addons/web/static/src/js/views/calendar/calendar_controller.js +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -54,7 +54,6 @@ var CalendarController = AbstractController.extend({ // Public //-------------------------------------------------------------------------- - /** * Render the buttons according to the CalendarView.buttons template and * add listeners on it. Set this.$buttons with the produced jQuery element @@ -154,10 +153,10 @@ var CalendarController = AbstractController.extend({ _onQuickCreate: function (event) { var self = this; this.model.createRecord(event) - .then(function (id) { + .then(function () { self.quick.destroy(); self.quick = null; - self.reload(id); + self.reload(); }, function (error, errorEvent) { // This will occurs if there are some more fields required // Preventdefaulting the error event will prevent the traceback window @@ -205,7 +204,6 @@ var CalendarController = AbstractController.extend({ if(!options.disableQuickCreate && !event.data.disableQuickCreate && this.quickAddPop) { this.quick = new QuickCreate(this, true, options, data, event.data); - this.quick.on('added', this, this.reload.bind(this)); this.quick.open(); this.quick.focus(); return; diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js index 4374421d7b3..b32374057bb 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -322,6 +322,7 @@ return AbstractModel.extend({ // List authorized values for every field // fields with an active 'all' filter are skipped var authorizedValues = {}; + var avoidValues = {}; _.each(this.data.filters, function (filter) { // Skip 'all' filters because they do not affect the domain @@ -329,11 +330,20 @@ return AbstractModel.extend({ // Loop over subfilters to complete authorizedValues _.each(filter.filters, function (f) { - if (!authorizedValues[filter.fieldName]) - authorizedValues[filter.fieldName] = []; + if (filter.write_model) { + if (!authorizedValues[filter.fieldName]) + authorizedValues[filter.fieldName] = []; - if (f.active) { - authorizedValues[filter.fieldName].push(f.value); + if (f.active) { + authorizedValues[filter.fieldName].push(f.value); + } + } else { + if (!avoidValues[filter.fieldName]) + avoidValues[filter.fieldName] = []; + + if (!f.active) { + avoidValues[filter.fieldName].push(f.value); + } } }); }); @@ -343,6 +353,9 @@ return AbstractModel.extend({ for (var field in authorizedValues) { domain.push([field, 'in', authorizedValues[field]]); } + for (var field in avoidValues) { + domain.push([field, 'not in', avoidValues[field]]); + } return domain; }, diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index d40e66317ed..8d41fba39e3 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -31,15 +31,15 @@ QUnit.module('Views', { event: { fields: { id: {string: "ID", type: "integer"}, - user_id: {string: "user", type: "many2one", relation: 'user'}, - partner_id: {string: "user", type: "many2one", relation: 'partner', related: 'user_id.partner_id'}, + user_id: {string: "user", type: "many2one", relation: 'user', default: session.uid}, + partner_id: {string: "user", type: "many2one", relation: 'partner', related: 'user_id.partner_id', default: 1}, name: {string: "name", type: "char"}, start_date: {string: "start date", type: "date"}, stop_date: {string: "stop date", type: "date"}, start: {string: "start datetime", type: "datetime"}, stop: {string: "stop datetime", type: "datetime"}, allday: {string: "allday", type: "boolean"}, - partner_ids: {string: "attendees", type: "one2many", relation: 'partner'}, + partner_ids: {string: "attendees", type: "one2many", relation: 'partner', default: [[6, 0, [1]]]}, type: {string: "type", type: "integer"}, }, records: [ @@ -1085,7 +1085,6 @@ QUnit.module('Views', { assert.strictEqual($('#ui-datepicker-div:empty').length, 0, "should have a clean body"); }); - QUnit.test('readonly date_start field', function (assert) { assert.expect(4); @@ -1207,6 +1206,305 @@ QUnit.module('Views', { calendar.destroy(); }); + QUnit.test('create event with filters', function (assert) { + assert.expect(7); + + this.data.event.fields.user_id.default = 5; + this.data.event.fields.partner_id.default = 3; + this.data.user.records.push({id: 5, display_name: "user 5", partner_id: 3}); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + ''+ + ''+ + ''+ + ''+ + '', + viewOptions: { + initialDate: initialDate, + }, + }); + + var $view = $('#qunit-fixture').contents(); + $view.prependTo('body'); // => select with click position + + calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + + assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 5, "should display 5 filter items"); + assert.strictEqual(calendar.$('.fc-event').length, 3, "should display 3 events"); + + // quick create a record + var left = calendar.$('.fc-bg td:eq(4)').offset().left+15; + var top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15; + try { + testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + } catch (e) { + calendar.destroy(); + $view.remove(); + throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); + } + testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); + testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); + + $('.modal-body input:first').val('coucou').trigger('input'); + $('.modal button.btn:contains(Create)').trigger('click'); + + assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should add the missing filter (active)"); + assert.strictEqual(calendar.$('.fc-event').length, 4, "should display the created item"); + + // change default value for quick create an hide record + this.data.event.fields.user_id.default = 4; + this.data.event.fields.partner_id.default = 4; + + // quick create and other record + left = calendar.$('.fc-bg td:eq(3)').offset().left+15; + top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15; + testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); + testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); + + $('.modal-body input:first').val('coucou 2').trigger('input'); + $('.modal button.btn:contains(Create)').trigger('click'); + + assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should have the same filters"); + assert.strictEqual(calendar.$('.fc-event').length, 4, "should not display the created item"); + + calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + + assert.strictEqual(calendar.$('.fc-event').length, 11, "should display all records"); + + calendar.destroy(); + $view.remove(); + }); + + QUnit.test('create event with filters (no quickCreate)', function (assert) { + assert.expect(4); + + this.data.event.fields.user_id.default = 5; + this.data.event.fields.partner_id.default = 3; + this.data.user.records.push({ + id: 5, + display_name: "user 5", + partner_id: 3 + }); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + ''+ + ''+ + ''+ + ''+ + '', + archs: { + "event,false,form": + '
'+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '
', + }, + viewOptions: { + initialDate: initialDate, + }, + }); + + var $view = $('#qunit-fixture').contents(); + $view.prependTo('body'); // => select with click position + + calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + + assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 5, "should display 5 filter items"); + assert.strictEqual(calendar.$('.fc-event').length, 3, "should display 3 events"); + + // quick create a record + var left = calendar.$('.fc-bg td:eq(4)').offset().left+15; + var top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15; + try { + testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + } catch (e) { + calendar.destroy(); + $view.remove(); + throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); + } + testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); + testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); + + $('.modal-body input:first').val('coucou').trigger('input'); + + $('.modal button.btn:contains(Edit)').trigger('click'); + $('.modal button.btn:contains(Save)').trigger('click'); + + assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should add the missing filter (active)"); + assert.strictEqual(calendar.$('.fc-event').length, 4, "should display the created item"); + + calendar.destroy(); + $view.remove(); + }); + + QUnit.test('Update event with filters', function (assert) { + assert.expect(4); + + var records = this.data.user.records; + records.push({ + id: 5, + display_name: "user 5", + partner_id: 3 + }); + + this.data.event.onchanges = { + user_id: function (obj) { + obj.partner_id = _.findWhere(records, {id:obj.user_id}).partner_id; + } + }; + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + ''+ + ''+ + ''+ + ''+ + '', + archs: { + "event,false,form": + '
'+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '
', + }, + viewOptions: { + initialDate: initialDate, + }, + }); + + calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + + assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 5, "should display 5 filter items"); + assert.strictEqual(calendar.$('.fc-event').length, 3, "should display 3 events"); + + calendar.$('.fc-event:contains(event 2) .fc-content').trigger('click'); + $('.modal button.btn:contains(Edit)').trigger('click'); + $('.modal .o_field_widget[name="user_id"] input').trigger('click'); + $('.ui-menu-item a:contains(user 5)').trigger('mouseenter').trigger('click'); + $('.modal button.btn:contains(Save)').trigger('click'); + + assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should add the missing filter (active)"); + assert.strictEqual(calendar.$('.fc-event').length, 3, "should display the updated item"); + + calendar.destroy(); + }); + + QUnit.test('change pager with filters', function (assert) { + assert.expect(3); + + this.data.user.records.push({ + id: 5, + display_name: "user 5", + partner_id: 3 + }); + this.data.event.records.push({ + id: 7, + user_id: 5, + partner_id: 3, + name: "event 7", + start: "2016-12-06 04:00:00", + stop: "2016-12-06 08:00:00", + allday: false, + partner_ids: [1,2,3], + type: 1 + }, { + id: 8, + user_id: session.uid, + partner_id: 1, + name: "event 8", + start: "2016-12-07 04:00:00", + stop: "2016-12-07 08:00:00", + allday: false, + partner_ids: [1,2,3], + type: 1 + },{ + id: 9, + user_id: 4, + partner_id: 4, + name: "event 9", + start: "2016-12-08 04:00:00", + stop: "2016-12-08 08:00:00", + allday: false, + partner_ids: [1,2,3], + type: 1 + }); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + ''+ + ''+ + ''+ + ''+ + '', + viewOptions: { + initialDate: initialDate, + }, + }); + + calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + $('.o_calendar_button_prev').click(); + + assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should display 6 filter items"); + assert.strictEqual(calendar.$('.fc-event').length, 2, "should display 2 events"); + assert.strictEqual(calendar.$('.fc-event .o_field_name').text().replace(/\s/g, ''), "event7event8", + "should display 2 events"); + + calendar.destroy(); + }); + QUnit.test('ensure events are still shown if filters give an empty domain', function (assert) { assert.expect(2);