diff --git a/addons/hr_timesheet/static/src/components/task_with_hours/task_with_hours.js b/addons/hr_timesheet/static/src/components/task_with_hours/task_with_hours.js index 22e1464d48b..ba82247cede 100644 --- a/addons/hr_timesheet/static/src/components/task_with_hours/task_with_hours.js +++ b/addons/hr_timesheet/static/src/components/task_with_hours/task_with_hours.js @@ -6,14 +6,6 @@ import { Many2OneField } from "@web/views/fields/many2one/many2one_field"; class TaskWithHours extends Many2OneField { - setup() { - super.setup(); - const activeActions = this.state.activeActions; - activeActions.canCreate = activeActions.canCreate && this.canCreate; - activeActions.canQuickCreate = activeActions.canQuickCreate || this.canCreate; - activeActions.canCreateEdit = activeActions.canCreate; - } - get canCreate() { return Boolean(this.context.default_project_id); } @@ -44,6 +36,16 @@ class TaskWithHours extends Many2OneField { return props; } + /** + * @override + */ + computeActiveActions(props) { + super.computeActiveActions(props); + const activeActions = this.state.activeActions; + activeActions.create = activeActions.create && this.canCreate; + activeActions.createEdit = activeActions.create; + } + } registry.category("fields").add("task_with_hours", TaskWithHours); diff --git a/addons/hr_timesheet/static/tests/hr_timesheet_common_tests.js b/addons/hr_timesheet/static/tests/hr_timesheet_common_tests.js new file mode 100644 index 00000000000..2973e580364 --- /dev/null +++ b/addons/hr_timesheet/static/tests/hr_timesheet_common_tests.js @@ -0,0 +1,130 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { session } from "@web/session"; +import { companyService } from "@web/webclient/company_service"; + +import { patchWithCleanup } from "@web/../tests/helpers/utils"; +import { setupViewRegistries } from "@web/../tests/views/helpers"; + + +export const getServerData = () => JSON.parse(JSON.stringify({ + models: { + 'account.analytic.line': { + fields: { + project_id: { string: "Project", type: "many2one", relation: "project.project" }, + task_id: { string: "Task", type: "many2one", relation: "project.task" }, + unit_amount: { string: "Unit Amount", type: "integer" }, + }, + records: [ + { id: 1, project_id: 1, task_id: 3, unit_amount: 1 }, + { id: 2, project_id: 1, task_id: false, unit_amount: 1 }, + { id: 3, project_id: false, task_id: false, unit_amount: 1 }, + ], + }, + 'project.project': { + fields: { + name: { string: "Name", type: "string" }, + }, + records: [ + { id: 1, name: "Project 1" }, + ], + }, + 'project.task': { + fields: { + name: { string: "Name", type: "string" }, + project_id: { string: "Project", type: "many2one", relation: "project.project" }, + }, + records: [ + { id: 1, name: "Task 1\u00A0AdditionalInfo", project_id: 1 }, + { id: 2, name: "Task 2\u00A0AdditionalInfo", project_id: 1 }, + { id: 3, name: "Task 3\u00A0AdditionalInfo", project_id: 1 }, + ], + }, + }, + views: { + "account.analytic.line,false,form": ` +
+ + + + + `, + "account.analytic.line,false,list": ` + + + + + + `, + }, +})); + +export function updateArch(serverData, fieldNameWidgetNameMapping = {}, fieldNameContextMapping = {}) { + for (const viewKey in serverData.views) { + for (const [fieldName, widgetName] of Object.entries(fieldNameWidgetNameMapping)) { + serverData.views[viewKey] = serverData.views[viewKey].replace( + `name="${fieldName}"`, + `name="${fieldName}" widget="${widgetName}"` + ); + } + for (const [fieldName, context] of Object.entries(fieldNameContextMapping)) { + serverData.views[viewKey] = serverData.views[viewKey].replace( + `name="${fieldName}"`, + `name="${fieldName}" context="${context}"` + ); + } + } +} + +export function addFieldsInArch(serverData, fields, beforeField) { + let fieldsArch = ""; + for (const field of fields) { + fieldsArch += ` + `; + } + for (const viewKey in serverData.views) { + serverData.views[viewKey] = serverData.views[viewKey].replace( + ` { + let target; + let serverData; + hooks.beforeEach(async function (assert) { + setupTestEnv(); + serverData = getServerData(); + updateArch( + serverData, + { task_id: "task_with_hours" }, + { task_id: "{ 'default_project_id': project_id }" }); + target = getFixture(); + }); + + QUnit.module("task_with_hours"); + + async function _testCreateAndEdit(target, visible, assert) { + await click(target, ".o_list_many2one[name=task_id]"); + await click(target, ".o_list_many2one[name=task_id] input"); + await editInput(target, ".o_list_many2one[name=task_id] input", "NonExistingTask"); + await click(target, ".o_list_many2one[name=task_id] input"); + await clickDropdown(target, "task_id"); + const testFunction = visible ? assert.containsOnce : assert.containsNone; + testFunction(target, '.o_list_many2one[name=task_id] .dropdown ul li:contains("Create and edit...")'); + } + + QUnit.test("quick create is enabled when project_id is set", async function (assert) { + await makeView({ + serverData, + type: "list", + resModel: "account.analytic.line", + }); + const secondRow = target.querySelector(".o_list_table .o_data_row:nth-of-type(2)"); + await _testCreateAndEdit(secondRow, true, assert); + }); + + QUnit.test("quick create is no enabled when project_id is not set", async function (assert) { + await makeView({ + serverData, + type: "list", + resModel: "account.analytic.line", + }); + const thirdRow = target.querySelector(".o_list_table .o_data_row:nth-of-type(3)"); + await _testCreateAndEdit(thirdRow, false, assert); + }); + + QUnit.test("the text of the task includes hours in the drop down but not in the line", async function (assert) { + await makeView({ + serverData, + type: "list", + resModel: "account.analytic.line", + }); + const firstRow = target.querySelector(".o_list_table .o_data_row:first-of-type"); + assert.containsNone(firstRow, '.o_list_many2one[name=task_id]:contains("AdditionalInfo")'); + await click(firstRow, ".o_list_many2one[name=task_id]"); + await clickDropdown(firstRow, "task_id"); + assert.containsN(firstRow, '.o_list_many2one[name=task_id] .dropdown ul li:contains("AdditionalInfo")', 3); + }); + +});