diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index ec777c2e12c..f194844707a 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -21,6 +21,7 @@ var dialogs = require('web.view_dialogs'); var core = require('web.core'); var data = require('web.data'); var Dialog = require('web.Dialog'); +var KanbanRecord = require('web.KanbanRecord'); var KanbanRenderer = require('web.KanbanRenderer'); var ListRenderer = require('web.ListRenderer'); var Pager = require('web.Pager'); @@ -1397,6 +1398,59 @@ var FieldX2Many = AbstractField.extend({ }, }); +var One2ManyKanbanRecord = KanbanRecord.extend({ + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Apply same logic as in the ListRenderer: buttons with type="object" + * are disabled for no saved yet records, as calling the python method + * with no id would make no sense. + * + * To avoid to expose this logic inside all Kanban views, we define + * a specific KanbanRecord Class for the One2many case. + * + * This could be refactored to prevent from duplicating this logic in + * list and kanban views. + * + * @private + */ + _postProcessObjectButtons: function () { + var self = this; + // if the res_id is defined, it's already correctly handled by the Kanban record global event click + if (!this.state.res_id) { + this.$('.oe_kanban_action[data-type=object]').each(function (index, button) { + var $button = $(button); + if ($button.attr('warn')) { + $button.on('click', function (e) { + e.stopPropagation(); + self.do_warn(_t('Warning'), _t('Please click on the "save" button first.')); + }); + } else { + $button.attr('disabled', 'disabled'); + } + }); + } + }, + /** + * @override + * @private + */ + _render: function () { + var self = this; + return this._super.apply(this, arguments).then(function () { + self._postProcessObjectButtons(); + }); + }, +}); + +var One2ManyKanbanRenderer = KanbanRenderer.extend({ + config: _.extend({}, KanbanRenderer.prototype.config, { + KanbanRecord: One2ManyKanbanRecord, + }), +}); + var FieldOne2Many = FieldX2Many.extend({ className: 'o_field_one2many', supportedFieldTypes: ['one2many'], @@ -1450,6 +1504,16 @@ var FieldOne2Many = FieldX2Many.extend({ // Private //-------------------------------------------------------------------------- + /** + * @override + * @private + */ + _getRenderer: function () { + if (this.view.arch.tag === 'kanban') { + return One2ManyKanbanRenderer; + } + return this._super.apply(this, arguments); + }, /** * Overrides to only render the buttons if the 'create' action is available. * diff --git a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js index 18581b88078..148242bffdb 100644 --- a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js +++ b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js @@ -4,7 +4,9 @@ odoo.define('web.field_one_to_many_tests', function (require) { var AbstractField = require('web.AbstractField'); var concurrency = require('web.concurrency'); var FormView = require('web.FormView'); +var KanbanRecord = require('web.KanbanRecord'); var ListRenderer = require('web.ListRenderer'); +var NotificationService = require('web.NotificationService'); var relationalFields = require('web.relational_fields'); var testUtils = require('web.test_utils'); var fieldUtils = require('web.field_utils'); @@ -5418,6 +5420,145 @@ QUnit.module('fields', {}, function () { form.destroy(); }); + QUnit.test('one2many field with virtual ids with kanban button', function (assert) { + assert.expect(25); + + testUtils.mock.patch(KanbanRecord, { + init: function () { + this._super.apply(this, arguments); + this._onKanbanActionClicked = this.__proto__._onKanbanActionClicked; + }, + }); + + this.data.partner.records[0].p = [4]; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
', + archs: { + 'partner,false,form': '
', + }, + res_id: 1, + services: { + notification: NotificationService.extend({ + notify: function (params) { + assert.step(params.type); + } + }), + }, + intercepts: { + execute_action: function (event) { + assert.step(event.data.action_data.name + '_' + event.data.env.model + '_' + event.data.env.currentID); + event.data.on_success(); + }, + }, + }); + + // 1. Define all css selector + var oKanbanView = '.o_field_widget .o_kanban_view'; + var oKanbanRecordActive = oKanbanView + ' .o_kanban_record:not(.o_kanban_ghost)'; + var oAllKanbanButton = oKanbanRecordActive + ' button[data-type="object"]'; + var btn1 = oKanbanRecordActive + ':nth-child(1) button[data-type="object"]'; + var btn2 = oKanbanRecordActive + ':nth-child(2) button[data-type="object"]'; + var btn1Warn = btn1 + '[data-name="button_warn"]'; + var btn1Disabled = btn1 + '[data-name="button_disabled"]'; + var btn2Warn = btn2 + '[data-name="button_warn"]'; + var btn2Disabled = btn2 + '[data-name="button_disabled"]'; + + // check if we already have one kanban card + assert.containsOnce(form, oKanbanView, "should have one inner kanban view for the one2many field"); + assert.containsOnce(form, oKanbanRecordActive, "should have one kanban records yet"); + + // we have 2 buttons + assert.containsN(form, oAllKanbanButton, 2, "should have 2 buttons type object"); + + // disabled ? + assert.containsNone(form, oAllKanbanButton + '[disabled]', "should not have button type object disabled"); + + // click on the button + testUtils.dom.click(form.$(btn1Disabled)); + testUtils.dom.click(form.$(btn1Warn)); + + // switch to edit mode + testUtils.form.clickEdit(form); + + // click on existing buttons + testUtils.dom.click(form.$(btn1Disabled)); + testUtils.dom.click(form.$(btn1Warn)); + + // create new kanban + testUtils.dom.click(form.$('.o_field_widget .o-kanban-button-new')); + + // save & close the modal + assert.strictEqual($('.modal-content input.o_field_widget').val(), 'My little Foo Value', + "should already have the default value for field foo"); + testUtils.dom.click($('.modal-content .btn-primary').first()); + + // check new item + assert.containsN(form, oAllKanbanButton, 4, "should have 4 buttons type object"); + assert.containsN(form, btn1, 2, "should have 2 buttons type object in area 1"); + assert.containsN(form, btn2, 2, "should have 2 buttons type object in area 2"); + assert.containsOnce(form, oAllKanbanButton + '[disabled]', "should have 1 button type object disabled"); + + assert.strictEqual(form.$(btn2Disabled).attr('disabled'), 'disabled', 'Should have a button type object disabled in area 2'); + assert.strictEqual(form.$(btn2Warn).attr('disabled'), undefined, 'Should have a button type object not disabled in area 2'); + assert.strictEqual(form.$(btn2Warn).attr('warn'), 'warn', 'Should have a button type object with warn attr in area 2'); + + // click all buttons + testUtils.dom.click(form.$(btn1Disabled)); + testUtils.dom.click(form.$(btn1Warn)); + testUtils.dom.click(form.$(btn2Disabled)); + testUtils.dom.click(form.$(btn2Warn)); + + // save the form + testUtils.form.clickSave(form); + + assert.containsNone(form, oAllKanbanButton + '[disabled]', "should not have button type object disabled after save"); + + // click all buttons + testUtils.dom.click(form.$(btn1Disabled)); + testUtils.dom.click(form.$(btn1Warn)); + testUtils.dom.click(form.$(btn2Disabled)); + testUtils.dom.click(form.$(btn2Warn)); + + assert.verifySteps([ + "button_disabled_partner_4", + "button_warn_partner_4", + + "button_disabled_partner_4", + "button_warn_partner_4", + + "button_disabled_partner_4", + "button_warn_partner_4", + "warning", // warn btn8 + + "button_disabled_partner_4", + "button_warn_partner_4", + "button_disabled_partner_8", + "button_warn_partner_8" + ], "should have triggered theses 11 clicks event"); + + testUtils.mock.unpatch(KanbanRecord); + form.destroy(); + }); + QUnit.test('focusing fields in one2many list', function (assert) { assert.expect(2);