From 6663ff97b66fb3169f36bbc44e6bcffa5715c228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 13 Sep 2018 17:53:12 +0200 Subject: [PATCH 1/6] [IMP] web: add an option to hide archive option in kanban columns Currently kanban columns propose an Archive / Unarchive option if the records model has an active field. It allows to directly archive or restore all records belonging to that column. It is currently not possible to control whether this option is present or not as it only depends on the active field being defined on the model. In some specific cases we want to be able to hide this option even if the active field exists. For example future commits will hide this option for leads (crm.lead) as business flow goes through marking them as won or lost instead of archiving / restoring them. This commit adds support of a new archivable parameter when defining the kanban view that hides the archive buttons if it is set to False. Default value is true so that current behavior is kept as it is by default. Doc and tests are added. This commit is linked to task ID 1880051 and PR #26977. --- .../src/js/views/kanban/kanban_column.js | 1 + .../static/src/js/views/kanban/kanban_view.js | 1 + addons/web/static/src/xml/kanban.xml | 2 +- addons/web/static/tests/views/kanban_tests.js | 71 ++++++++++++++++++- doc/reference/views.rst | 3 + 5 files changed, 76 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/views/kanban/kanban_column.js b/addons/web/static/src/js/views/kanban/kanban_column.js index 6fea1c36d32..ef75caca8c0 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column.js +++ b/addons/web/static/src/js/views/kanban/kanban_column.js @@ -53,6 +53,7 @@ var KanbanColumn = Widget.extend({ this.grouped_by_m2o = options.grouped_by_m2o; this.editable = options.editable; this.deletable = options.deletable; + this.archivable = options.archivable; this.draggable = options.draggable; this.KanbanRecord = options.KanbanRecord || KanbanRecord; // the KanbanRecord class to use this.records_editable = options.records_editable; diff --git a/addons/web/static/src/js/views/kanban/kanban_view.js b/addons/web/static/src/js/views/kanban/kanban_view.js index 99be6175da3..791e3664668 100644 --- a/addons/web/static/src/js/views/kanban/kanban_view.js +++ b/addons/web/static/src/js/views/kanban/kanban_view.js @@ -61,6 +61,7 @@ var KanbanView = BasicView.extend({ this.rendererParams.column_options = { editable: activeActions.group_edit, deletable: activeActions.group_delete, + archivable: this.arch.attrs.archivable ? JSON.parse(this.arch.attrs.archivable) : true, group_creatable: activeActions.group_create && !config.device.isMobile, quick_create: params.isQuickCreateEnabled || this._isQuickCreateEnabled(), quickCreateView: this.arch.attrs.quick_create_view || null, diff --git a/addons/web/static/src/xml/kanban.xml b/addons/web/static/src/xml/kanban.xml index adc213999f2..b91b8844752 100644 --- a/addons/web/static/src/xml/kanban.xml +++ b/addons/web/static/src/xml/kanban.xml @@ -23,7 +23,7 @@ Edit Stage Delete - + Archive All Unarchive All diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index c967b42a332..1fbe683187d 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -148,7 +148,7 @@ QUnit.module('Views', { kanban.destroy(); }); - QUnit.test('basic grouped rendering with active field', function (assert) { + QUnit.test('basic grouped rendering with active field (archivable by default)', function (assert) { assert.expect(9); // add active field on partner model and make all records active @@ -193,6 +193,75 @@ QUnit.module('Views', { kanban.destroy(); }); + QUnit.test('basic grouped rendering with active field and archive enabled (archivable true)', function (assert) { + assert.expect(7); + + // add active field on partner model and make all records active + this.data.partner.fields.active = {string: 'Active', type: 'char', default: true}; + + var envIDs = [1, 2, 3, 4]; // the ids that should be in the environment during this test + var kanban = createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '' + + '' + + '' + + '' + + '
' + + '
', + groupBy: ['bar'], + }); + + // check archive/restore all actions in kanban header's config dropdown + assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive_records').length, "should be able to archive all the records"); + assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive_records').length, "should be able to restore all the records"); + + // archive the records of the first column + assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3, + "last column should contain 3 records"); + envIDs = [4]; + kanban.$('.o_kanban_group:last .o_column_archive_records').click(); // Click on 'Archive All' + assert.ok($('.modal').length, 'a confirm modal should be displayed'); + $('.modal-footer .btn-secondary').click(); // Click on 'Cancel' + assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3, "still last column should contain 3 records"); + kanban.$('.o_kanban_group:last .o_column_archive_records').click(); + assert.ok($('.modal').length, 'a confirm modal should be displayed'); + $('.modal-footer .btn-primary').click(); // Click on 'Ok' + assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 0, "last column should not contain any records"); + kanban.destroy(); + }); + + QUnit.test('basic grouped rendering with active field and hidden archive buttons (archivable false)', function (assert) { + assert.expect(2); + + // add active field on partner model and make all records active + this.data.partner.fields.active = {string: 'Active', type: 'char', default: true}; + + var envIDs = [1, 2, 3, 4]; // the ids that should be in the environment during this test + var kanban = createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '' + + '' + + '' + + '' + + '
' + + '
', + groupBy: ['bar'], + }); + + // check archive/restore all actions in kanban header's config dropdown + assert.strictEqual( + kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive_records').length, 0, + "should not be able to archive all the records"); + assert.strictEqual( + kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive_records').length, 0, + "should not be able to restore all the records"); + kanban.destroy(); + }); + QUnit.test('pager should be hidden in grouped mode', function (assert) { assert.expect(1); diff --git a/doc/reference/views.rst b/doc/reference/views.rst index 052c63a97f5..373a31b022a 100644 --- a/doc/reference/views.rst +++ b/doc/reference/views.rst @@ -998,6 +998,9 @@ attributes: whether groups can be deleted via the context menu. Default: true. ``group_edit`` whether groups can be edited via the context menu. Default: true. +``archivable`` + whether records belonging to a column can be archived / restored if an + ``active`` field is defined on the model. Default: true. ``quick_create`` whether it should be possible to create records without switching to the form view. By default, ``quick_create`` is enabled when the Kanban view is From 1fea0f18a8180387fd0ef4f7d34bae07a9f12139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 13 Sep 2018 14:51:46 +0200 Subject: [PATCH 2/6] [IMP] sale_crm: hide 'New Quotation' button if opportunity is lost A lost opportunity is archived and should not have primary actions buttons. First thing to do would be to restore it before having access to some other actions. This commit is linked to task ID 1880051 and PR #26977. --- addons/sale_crm/views/crm_lead_views.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/sale_crm/views/crm_lead_views.xml b/addons/sale_crm/views/crm_lead_views.xml index 5efb023bfd3..a238063fef5 100644 --- a/addons/sale_crm/views/crm_lead_views.xml +++ b/addons/sale_crm/views/crm_lead_views.xml @@ -8,6 +8,7 @@ -
Won
+
Lost
+
Won
- -
Lost
-
Won
+
Lost
+
Won
@@ -407,7 +406,7 @@ + domain="['&', ('probability', '=', 0), ('active', '=', False)]"/> From 0627ca78fbe823daccc32a5b8c614a0e042462e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Sep 2018 09:25:45 +0200 Subject: [PATCH 5/6] [IMP] crm: track active state of leads and opps Purpose of this commit is to ease the tracking of won / lost state of leads and opportunities by tracking the active status. This commit is linked to task ID 1880051 and PR #26977. --- addons/crm/models/crm_lead.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 16be1c0160b..fe96108292c 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -66,7 +66,7 @@ class Lead(models.Model): name = fields.Char('Opportunity', required=True, index=True) partner_id = fields.Many2one('res.partner', string='Customer', track_visibility='onchange', track_sequence=1, index=True, help="Linked partner (optional). Usually created when converting the lead.") - active = fields.Boolean('Active', default=True) + active = fields.Boolean('Active', default=True, track_visibility=True) date_action_last = fields.Datetime('Last Action', readonly=True) email_from = fields.Char('Email', help="Email address of the contact", track_visibility='onchange', track_sequence=4, index=True) website = fields.Char('Website', index=True, help="Website of the contact") From 22e33a7a3d57e1fac63585703ff4cd3a39d4b3e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Sep 2018 09:32:38 +0200 Subject: [PATCH 6/6] [IMP] crm: restore default stage probably when restoring leads Purpose of this commit is to avoid having restored leads and opportunities having always 0 probability even if the stage has an high probably than that. This commit is linked to task ID 1880051 and PR #26977. --- addons/crm/models/crm_lead.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index fe96108292c..b6829a25708 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -451,6 +451,14 @@ class Lead(models.Model): 'context': {'default_type': 'opportunity'} } + def toggle_active(self): + """ When re-activating leads and opportunities set their probability + to the default stage one. """ + res = super(Lead, self).toggle_active() + for lead in self.filtered(lambda lead: lead.active and lead.stage_id.probability): + lead.probability = lead.stage_id.probability + return res + # ---------------------------------------- # Business Methods # ----------------------------------------