From 8bd94f422f50dce146e953bbddf356cb1252e7c0 Mon Sep 17 00:00:00 2001 From: "Audric Onockx (auon)" Date: Wed, 23 Feb 2022 12:40:36 +0000 Subject: [PATCH] [FIX] project : keep one task as model for recurrence Steps : Create a recurrent task. Delete it. Run the cron "Create Recurring Tasks". Issue : IndexError: tuple index out of range. Cause : The cron calls a method which takes the last task of the recurrence as a model. As there is no such task, an python error is thrown. Fix : Do not display the "Continue Recurrence" button when deleting the last task of it. opw-2743788 closes odoo/odoo#86309 X-original-commit: 9cfe0042dd6846cf8b52aebeb9dd6e7432b32322 Signed-off-by: Laurent Stukkens (ltu) --- addons/project/static/src/js/project_list.js | 75 +++++++++++++++----- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/addons/project/static/src/js/project_list.js b/addons/project/static/src/js/project_list.js index 4cbcb102a18..baee361e827 100644 --- a/addons/project/static/src/js/project_list.js +++ b/addons/project/static/src/js/project_list.js @@ -39,14 +39,45 @@ const ProjectListController = ListController.extend({ return this._super(...arguments); }, - _stopRecurrence(recurringResIds, resIds, mode) { + _countRecordsPerReccurence(recurrenceIds, resIds) { + return this._rpc({ + model: 'project.task', + method: 'read_group', + args: [ + [['recurrence_id', 'in', recurrenceIds], ['id', 'not in', resIds]], + ['recurrence_id'], + ['recurrence_id'], + ], + }); + }, + + async _stopRecurrence(recurringResIds, resIds, mode) { + const recurrenceIdsSet = new Set(); + for (const record of this.getSelectedRecords()) { + const recurrenceId = record.data.recurrence_id; + if (recurrenceId) { + recurrenceIdsSet.add(recurrenceId); + } + } + const recurrenceIds = Array.from(recurrenceIdsSet); + // list recurrences that have tasks left after deleting/archiving + let countsLeft = await this._countRecordsPerReccurence(recurrenceIds, recurringResIds); + countsLeft = countsLeft.map(rec => rec.recurrence_id[0]); + // so we check that no recurrence is absent, as it would mean no task is left + const allowContinue = recurrenceIds.every(rec => countsLeft.includes(rec)); + let warning; if (resIds.length > 1) { - warning = _t('It seems that some tasks are part of a recurrence.'); + warning = allowContinue + ? _t('It seems that some tasks are part of a recurrence.') + : _t('It seems that some tasks are part of a recurrence. At least one of them must be kept as a model to create the next occurences.'); } else { - warning = _t('It seems that this task is part of a recurrence.'); + warning = allowContinue + ? _t('It seems that this task is part of a recurrence.') + : _t('It seems that this task is part of a recurrence. You must keep it as a model to create the next occurences.'); } - return new Dialog(this, { + + const dialog = new Dialog(this, { buttons: [ { classes: 'btn-primary', @@ -66,6 +97,21 @@ const ProjectListController = ListController.extend({ close: true, text: _t('Stop Recurrence'), }, + { + close: true, + text: _t('Discard'), + } + ], + size: 'medium', + title: _t('Confirmation'), + $content: $('
', { + role: 'alert', + text: warning, + }), + }); + + if (allowContinue) { + Dialog.buttons.splice(0, 1, { click: () => { this._rpc({ @@ -79,22 +125,13 @@ const ProjectListController = ListController.extend({ this._deleteRecords(resIds); } }); - }, - close: true, - text: _t('Continue Recurrence'), }, - { - close: true, - text: _t('Discard'), - } - ], - size: 'medium', - title: _t('Confirmation'), - $content: $('
', { - role: 'alert', - text: warning, - }), - }).open(); + close: true, + text: _t('Continue Recurrence'), + }); + } + + dialog.open(); } });