Skip to content

Commit b2192ff

Browse files
committed
[FIX] hr_work_entry: No work entry type
Problem ---------- - If the user creates a work entry without a work entry type, it will fetch "false" id work entry type. It raises a traceback - Create a work entry without work entry type will change its state to conflict but if you add a work entry type the state will not change. - If you edit a correct work entry by removing the work entry type, the state will stay in draft, it will not become in conflict Fix ---------- - False work entry types are filtered in the favorite work entry type. - The work_entry_type_field widget is improved to not display a colored case if no work entry type is specified in the field. - The conflict behavior is fixed, a work entry without a work entry type should be in conflict. task-5078885 closes odoo#227956 Related: odoo/enterprise#95149 Signed-off-by: Yannick Tivisse (yti) <[email protected]>
1 parent a11e641 commit b2192ff

File tree

11 files changed

+182
-5
lines changed

11 files changed

+182
-5
lines changed

addons/hr_work_entry/__manifest__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
],
2626
'assets': {
2727
'web.assets_backend': [
28-
'hr_work_entry/static/**/*',
28+
'hr_work_entry/static/src/**/*',
29+
],
30+
'web.assets_unit_tests': [
31+
'hr_work_entry/static/tests/**/*',
2932
],
3033
},
3134
'author': 'Odoo S.A.',

addons/hr_work_entry/models/hr_work_entry.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,8 @@ def _error_checking(self, start=None, stop=None, skip=False, employee_ids=False)
282282
stop = stop or max(self.mapped('date'), default=False)
283283
if not skip and start and stop:
284284
domain = (
285-
Domain('date', '<', stop)
286-
& Domain('date', '>', start)
285+
Domain('date', '<=', stop)
286+
& Domain('date', '>=', start)
287287
& Domain('state', 'not in', ('validated', 'cancelled'))
288288
)
289289
if employee_ids:

addons/hr_work_entry/static/src/components/work_entry_type_field/work_entry_type_field.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export class WorkEntryType extends Component {
1919
}
2020

2121
function extractData(record) {
22+
if (!record) {
23+
return null;
24+
}
2225
let name;
2326
if ("display_name" in record) {
2427
name = record.display_name;

addons/hr_work_entry/static/src/components/work_entry_type_field/work_entry_type_field.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<templates id="template" xml:space="preserve">
33
<t t-name="hr_work_entry.Many2OneWorkEntryTypeField">
44
<div class="d-flex align-items-center gap-1">
5-
<t t-if="value !== false">
5+
<t t-if="m2oProps.value !== false">
66
<WorkEntryType data="state.data"/>
77
</t>
88
<Many2One t-props="m2oProps" cssClass="'w-100'">

addons/hr_work_entry/static/src/views/work_entry_calendar/work_entry_calendar_model.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export class WorkEntryCalendarModel extends CalendarModel {
4444
if (userFavoritesWorkEntriesIds.length) {
4545
this.userFavoritesWorkEntries = await this.orm.read(
4646
"hr.work.entry.type",
47-
userFavoritesWorkEntriesIds.map((r) => r.work_entry_type_id[0]),
47+
userFavoritesWorkEntriesIds.map((r) => r.work_entry_type_id?.[0]).filter(Boolean),
4848
["display_name", "display_code", "color"]
4949
);
5050
this.userFavoritesWorkEntries = this.userFavoritesWorkEntries.sort((a, b) =>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { defineModels } from "@web/../tests/web_test_helpers";
2+
import { hrModels } from "@hr/../tests/hr_test_helpers";
3+
import { HrEmployee } from "@hr_work_entry/../tests/mock_server/mock_models/hr_employee";
4+
import { HrWorkEntryType } from "@hr_work_entry/../tests/mock_server/mock_models/hr_work_entry_type";
5+
import { HrWorkEntry } from "@hr_work_entry/../tests/mock_server/mock_models/hr_work_entry";
6+
7+
export function defineHrWorkEntryModels() {
8+
return defineModels(hrWorkEntryModels);
9+
}
10+
11+
export const hrWorkEntryModels = {
12+
...hrModels,
13+
HrEmployee,
14+
HrWorkEntry,
15+
HrWorkEntryType,
16+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { models } from "@web/../tests/web_test_helpers";
2+
3+
export class HrEmployee extends models.ServerModel {
4+
_name = "hr.employee";
5+
6+
_records = [
7+
{ id: 100, name: "Richard" },
8+
{ id: 200, name: "Alice" },
9+
];
10+
11+
async generate_work_entries(employeeIds, startDate, endDate) {}
12+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { models } from "@web/../tests/web_test_helpers";
2+
3+
export class HrWorkEntry extends models.ServerModel {
4+
_name = "hr.work.entry";
5+
6+
_views = {
7+
"form,multi_create_form": `
8+
<form>
9+
<field name="employee_id" invisible="1"/>
10+
</form>
11+
`,
12+
calendar: `
13+
<calendar
14+
date_start="date"
15+
date_stop="date"
16+
mode="month"
17+
scales="month"
18+
month_overflow="0"
19+
quick_create="0"
20+
color="color"
21+
event_limit="9"
22+
show_date_picker="0"
23+
multi_create_view="multi_create_form"
24+
js_class="work_entries_calendar">
25+
</calendar>
26+
`,
27+
};
28+
29+
action_split(workEntryIds, vals) {}
30+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { models } from "@web/../tests/web_test_helpers";
2+
3+
export class HrWorkEntryType extends models.ServerModel {
4+
_name = "hr.work.entry.type";
5+
6+
_records = [
7+
{
8+
id: 1,
9+
name: "Test Work Entry Type",
10+
color: 1,
11+
display_code: "WT1",
12+
},
13+
{
14+
id: 2,
15+
name: "WET no color",
16+
color: false,
17+
display_code: "WT2",
18+
},
19+
{
20+
id: 3,
21+
name: "WET no display code",
22+
color: 1,
23+
display_code: false,
24+
},
25+
];
26+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { beforeEach, describe, expect, test } from "@odoo/hoot";
2+
import { animationFrame, mockDate } from "@odoo/hoot-mock";
3+
import { findComponent, makeMockServer, mountView } from "@web/../tests/web_test_helpers";
4+
import { defineHrWorkEntryModels } from "@hr_work_entry/../tests/hr_work_entry_test_helpers";
5+
import { WorkEntryCalendarController } from "@hr_work_entry/views/work_entry_calendar/work_entry_calendar_controller";
6+
const { DateTime } = luxon;
7+
8+
describe.current.tags("desktop");
9+
defineHrWorkEntryModels();
10+
11+
beforeEach(() => {
12+
mockDate("2025-01-01 12:00:00", +0);
13+
});
14+
15+
function getCalendarController(view) {
16+
return findComponent(view, (c) => c instanceof WorkEntryCalendarController);
17+
}
18+
19+
test("Test work entry calendar without work entry type", async () => {
20+
const { env } = await makeMockServer();
21+
env["hr.work.entry"].create([
22+
{
23+
name: "Test Work Entry 0",
24+
employee_id: 100,
25+
work_entry_type_id: false,
26+
date: "2025-01-01",
27+
duration: 120,
28+
},
29+
]);
30+
const calendar = await mountView({
31+
type: "calendar",
32+
resModel: "hr.work.entry",
33+
});
34+
expect(".o_calendar_renderer").toBeDisplayed({
35+
message:
36+
"Calendar view should be displayed even with work entries with false work entry type",
37+
});
38+
const controller = getCalendarController(calendar);
39+
const data = {
40+
name: "Test New Work Entry",
41+
employee_id: 100,
42+
work_entry_type_id: false,
43+
};
44+
await controller.model.multiCreateRecords(
45+
{
46+
record: {
47+
getChanges: () => data,
48+
},
49+
},
50+
[DateTime.fromISO("2025-01-02")]
51+
);
52+
await animationFrame();
53+
expect(".fc-event").toHaveCount(2, {
54+
message: "2 work entries should be displayed in the calendar view",
55+
});
56+
});

0 commit comments

Comments
 (0)