From 722e378f58d8c89a26f74e6d822223463dbe1c12 Mon Sep 17 00:00:00 2001 From: Unai Beristain Aramendi Date: Wed, 11 Jun 2025 16:00:31 +0200 Subject: [PATCH 1/4] [ADD] hr_attendance_custom_form: Add custom form link --- hr_attendance_custom_form/README.rst | 71 +++++++++++++++++++ hr_attendance_custom_form/__init__.py | 0 hr_attendance_custom_form/__manifest__.py | 19 +++++ .../static/src/js/hr_attendance_custom.js | 38 ++++++++++ .../src/xml/hr_attendance_custom_remove.xml | 36 ++++++++++ .../xml/hr_attendance_custom_templates.xml | 33 +++++++++ 6 files changed, 197 insertions(+) create mode 100644 hr_attendance_custom_form/README.rst create mode 100644 hr_attendance_custom_form/__init__.py create mode 100644 hr_attendance_custom_form/__manifest__.py create mode 100644 hr_attendance_custom_form/static/src/js/hr_attendance_custom.js create mode 100644 hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml create mode 100644 hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml diff --git a/hr_attendance_custom_form/README.rst b/hr_attendance_custom_form/README.rst new file mode 100644 index 00000000..d8f43c97 --- /dev/null +++ b/hr_attendance_custom_form/README.rst @@ -0,0 +1,71 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg + :target: https://www.gnu.org/licenses/lgpl-3.0.html + :alt: License: LGPL-3 + +=============================================================================== +HR Attendance Custom Form +=============================================================================== + +Overview +======== + +The **HR Attendance Custom Form** module customizes the default HR attendance kiosk interface in Odoo. It hides the default Odoo navigation elements (like the control panel and navbar) and extends the attendance kiosk screen with new buttons that provide quick access to the employee form and attendance calendar. + +Features +======== + +- Hides the Odoo **NavBar**, **ControlPanel**, and **FormControlPanel** when in kiosk mode. +- Replaces the numeric keypad layout in the kiosk attendance view. +- Adds the following custom buttons to the kiosk interface: + + - **"Go to employee profile"**: Opens the current employee's form view. + - **"Go to calendar"**: Opens a calendar view of the employee's attendances. + +Usage +===== + +1. Navigate to the **Attendances > Kiosk Mode**. +2. Enter your PIN to confirm attendance. +3. On the confirmation screen, the keypad will be customized and will show: + - Number pad and OK button + + - New buttons: + + - **Go to employee profile**: Takes you to the HR employee record. + + - **Go to calendar**: Opens a calendar showing the employee’s attendance records. + +These buttons are especially useful for HR or team leads to quickly verify employee records or schedules from the kiosk. + +Technical Details +================= + +- This module uses `t-extend` to modify the `HrAttendanceKioskConfirm` template. +- OWL templates and JavaScript are used to add behavior to the new buttons. +- Inherited templates (`web.ControlPanel`, `web.FormControlPanel`, `web.NavBar`) are overridden to hide standard UI elements during kiosk mode. + +Configuration +============= + +No additional configuration is needed. Simply install the module and open the **Kiosk Mode** view. + +Bug Tracker +=========== + +If you encounter any issues, please report them on the issue tracker: +`GitHub Issues `_. + +Credits +======= + +Contributors +------------ + +* Ana Juaristi +* Unai Beristain + +License +======= + +This project is licensed under the LGPL-3 License. +See: https://www.gnu.org/licenses/lgpl-3.0.html diff --git a/hr_attendance_custom_form/__init__.py b/hr_attendance_custom_form/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/hr_attendance_custom_form/__manifest__.py b/hr_attendance_custom_form/__manifest__.py new file mode 100644 index 00000000..310d8f8d --- /dev/null +++ b/hr_attendance_custom_form/__manifest__.py @@ -0,0 +1,19 @@ +{ + "name": "HR Attendance Custom Form", + "version": "16.0.1.0.0", + "category": "Human Resources", + "summary": "Custom HR Attendance Form", + "author": "Avanzosc", + "license": "LGPL-3", + "depends": ["hr_attendance", "web"], + "assets": { + "web.assets_backend": [ + "hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml", + "hr_attendance_custom_form/static/src/js/hr_attendance_custom.js", + "hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml", + ], + }, + "installable": True, + "application": False, + "auto_install": False, +} diff --git a/hr_attendance_custom_form/static/src/js/hr_attendance_custom.js b/hr_attendance_custom_form/static/src/js/hr_attendance_custom.js new file mode 100644 index 00000000..3b65654b --- /dev/null +++ b/hr_attendance_custom_form/static/src/js/hr_attendance_custom.js @@ -0,0 +1,38 @@ +/** @odoo-module **/ + +import KioskConfirm from "hr_attendance.kiosk_confirm"; +import {_t} from "web.core"; + +KioskConfirm.include({ + events: Object.assign({}, KioskConfirm.prototype.events, { + "click .o_hr_attendance_pin_pad_button_Go_to_employee_profile": function () { + console.log("Go to employee profile clicked for employee ID:", this.employee_id); + this.do_action({ + type: "ir.actions.act_window", + res_model: "hr.employee", + res_id: this.employee_id, + views: [[false, "form"]], + target: "current", + context: this.getSession().user_context, + }); + }, + "click .o_hr_attendance_pin_pad_button_Go_to_calendar": function () { + console.log("Go to calendar clicked for employee ID:", this.employee_id); + this.do_action({ + type: "ir.actions.act_window", + res_model: "hr.attendance", + views: [[false, "list"]], + target: "current", + context: Object.assign({}, this.getSession().user_context, { + search_default_employee_id: this.employee_id, + calendar_fields: { + date_start: "check_in", + date_stop: "check_out", + }, + }), + view_mode: "calendar", + view_type: "calendar", + }); + }, + }), +}); diff --git a/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml new file mode 100644 index 00000000..9a8699a7 --- /dev/null +++ b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml @@ -0,0 +1,36 @@ + + \ No newline at end of file diff --git a/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml new file mode 100644 index 00000000..2a0f8f79 --- /dev/null +++ b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml @@ -0,0 +1,33 @@ + + + + +
+
+
+
+ +
+
+
+ +
+ + + +
+
+
+
+
+
+
+ + +
\ No newline at end of file From 0b5856af902b1038a25dbf216f83c254af817d8c Mon Sep 17 00:00:00 2001 From: Unai Beristain Aramendi Date: Wed, 11 Jun 2025 19:07:26 +0200 Subject: [PATCH 2/4] [IMP] hr_attendance_custom_form: Update debug information to display user_id instead of env.config --- hr_attendance_custom_form/__manifest__.py | 5 +- .../static/src/js/navbar_inherit.js | 18 +++ .../src/xml/hr_attendance_custom_remove.xml | 136 ++++++++++++++---- .../xml/hr_attendance_custom_templates.xml | 2 +- 4 files changed, 130 insertions(+), 31 deletions(-) create mode 100644 hr_attendance_custom_form/static/src/js/navbar_inherit.js diff --git a/hr_attendance_custom_form/__manifest__.py b/hr_attendance_custom_form/__manifest__.py index 310d8f8d..3fdf770d 100644 --- a/hr_attendance_custom_form/__manifest__.py +++ b/hr_attendance_custom_form/__manifest__.py @@ -8,9 +8,8 @@ "depends": ["hr_attendance", "web"], "assets": { "web.assets_backend": [ - "hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml", - "hr_attendance_custom_form/static/src/js/hr_attendance_custom.js", - "hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml", + "hr_attendance_custom_form/static/src/js/**/*", + "hr_attendance_custom_form/static/src/xml/**/*", ], }, "installable": True, diff --git a/hr_attendance_custom_form/static/src/js/navbar_inherit.js b/hr_attendance_custom_form/static/src/js/navbar_inherit.js new file mode 100644 index 00000000..c5241a76 --- /dev/null +++ b/hr_attendance_custom_form/static/src/js/navbar_inherit.js @@ -0,0 +1,18 @@ +/** @odoo-module **/ + +import { NavBar as parentNavBar } from "@web/webclient/navbar/navbar"; +import { patch } from "@web/core/utils/patch"; + +patch(parentNavBar.prototype, "hr_attendance_custom_form.systray_items_patch", { + get systrayItems() { + const menuItems = this._super(); + console.log("Original systrayItems:", menuItems); + if (!Array.isArray(menuItems)) { + console.warn("systrayItems is not an array or is undefined:", menuItems); + return []; + } + const filteredItems = menuItems.filter(item => item.key === "web.user_menu"); + console.log("Filtered systrayItems (web.user_menu):", filteredItems); + return filteredItems; + } +}); \ No newline at end of file diff --git a/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml index 9a8699a7..a36fa69e 100644 --- a/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml +++ b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml @@ -1,36 +1,118 @@ - \ No newline at end of file + diff --git a/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml index 2a0f8f79..b3bc42ab 100644 --- a/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml +++ b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_templates.xml @@ -14,7 +14,7 @@
- +
From 20e3002e5d9d316d5949baf6743045b3ea5ed0a0 Mon Sep 17 00:00:00 2001 From: Unai Date: Fri, 13 Jun 2025 12:02:56 +0200 Subject: [PATCH 3/4] [ADD] hr_attendance_custom_form: Change js to odoo.define --- hr_attendance_custom_form/__manifest__.py | 1 + .../static/src/js/hr_attendance_custom.js | 93 ++++++++----- .../static/src/js/navbar_inherit.js | 28 ++-- .../src/xml/hr_attendance_custom_remove.xml | 123 ++++++++++++------ .../xml/hr_attendance_custom_templates.xml | 22 ++-- .../odoo/addons/hr_attendance_custom_form | 1 + setup/hr_attendance_custom_form/setup.py | 6 + 7 files changed, 180 insertions(+), 94 deletions(-) create mode 120000 setup/hr_attendance_custom_form/odoo/addons/hr_attendance_custom_form create mode 100644 setup/hr_attendance_custom_form/setup.py diff --git a/hr_attendance_custom_form/__manifest__.py b/hr_attendance_custom_form/__manifest__.py index 3fdf770d..3e4b8124 100644 --- a/hr_attendance_custom_form/__manifest__.py +++ b/hr_attendance_custom_form/__manifest__.py @@ -6,6 +6,7 @@ "author": "Avanzosc", "license": "LGPL-3", "depends": ["hr_attendance", "web"], + "website": "https://github.com/avanzosc/hr-addons", "assets": { "web.assets_backend": [ "hr_attendance_custom_form/static/src/js/**/*", diff --git a/hr_attendance_custom_form/static/src/js/hr_attendance_custom.js b/hr_attendance_custom_form/static/src/js/hr_attendance_custom.js index 3b65654b..3ab408c4 100644 --- a/hr_attendance_custom_form/static/src/js/hr_attendance_custom.js +++ b/hr_attendance_custom_form/static/src/js/hr_attendance_custom.js @@ -1,38 +1,59 @@ -/** @odoo-module **/ +odoo.define( + "hr_attendance_custom_form.kiosk_confirm_patch", + ["hr_attendance.kiosk_confirm", "web.core"], + function (require) { + "use strict"; -import KioskConfirm from "hr_attendance.kiosk_confirm"; -import {_t} from "web.core"; + const KioskConfirm = require("hr_attendance.kiosk_confirm"); -KioskConfirm.include({ - events: Object.assign({}, KioskConfirm.prototype.events, { - "click .o_hr_attendance_pin_pad_button_Go_to_employee_profile": function () { - console.log("Go to employee profile clicked for employee ID:", this.employee_id); - this.do_action({ - type: "ir.actions.act_window", - res_model: "hr.employee", - res_id: this.employee_id, - views: [[false, "form"]], - target: "current", - context: this.getSession().user_context, - }); - }, - "click .o_hr_attendance_pin_pad_button_Go_to_calendar": function () { - console.log("Go to calendar clicked for employee ID:", this.employee_id); - this.do_action({ - type: "ir.actions.act_window", - res_model: "hr.attendance", - views: [[false, "list"]], - target: "current", - context: Object.assign({}, this.getSession().user_context, { - search_default_employee_id: this.employee_id, - calendar_fields: { - date_start: "check_in", - date_stop: "check_out", - }, - }), - view_mode: "calendar", - view_type: "calendar", - }); - }, - }), -}); + KioskConfirm.include({ + events: Object.assign({}, KioskConfirm.prototype.events, { + "click .o_hr_attendance_pin_pad_button_Go_to_employee_profile": function () { + this.update_attendance((result) => { + if (result?.warning) { + this.displayNotification({ title: result.warning, type: "danger" }); + } else { + this.do_action({ + type: "ir.actions.act_window", + res_model: "hr.employee", + res_id: this.employee_id, + views: [[false, "form"]], + target: "current", + context: Object.assign({}, this.getSession().user_context, { + employee_id: this.employee_id, + }), + domain: [["id", "=", this.employee_id]], + }); + } + }); + }, + + "click .o_hr_attendance_pin_pad_button_Go_to_calendar": function () { + this.update_attendance((result) => { + if (result?.warning) { + this.displayNotification({ title: result.warning, type: "danger" }); + } else { + this.do_action({ + type: "ir.actions.act_window", + res_model: "hr.attendance", + views: [[false, "calendar"]], + target: "current", + context: Object.assign({}, this.getSession().user_context, { + employee_id: this.employee_id, + search_default_employee_id: this.employee_id, + calendar_fields: { + date_start: "check_in", + date_stop: "check_out", + }, + }), + domain: [["employee_id", "=", this.employee_id]], + view_mode: "calendar", + view_type: "calendar", + }); + } + }); + }, + }), + }); + } +); diff --git a/hr_attendance_custom_form/static/src/js/navbar_inherit.js b/hr_attendance_custom_form/static/src/js/navbar_inherit.js index c5241a76..405cbfbb 100644 --- a/hr_attendance_custom_form/static/src/js/navbar_inherit.js +++ b/hr_attendance_custom_form/static/src/js/navbar_inherit.js @@ -1,18 +1,24 @@ -/** @odoo-module **/ +odoo.define( + "hr_attendance_custom_form.systray_items_patch", + ["web.NavBar", "web.utils"], + function (require) { + "use strict"; -import { NavBar as parentNavBar } from "@web/webclient/navbar/navbar"; -import { patch } from "@web/core/utils/patch"; + const NavBar = require("web.NavBar"); + const {patch} = require("web.utils"); -patch(parentNavBar.prototype, "hr_attendance_custom_form.systray_items_patch", { - get systrayItems() { - const menuItems = this._super(); + patch(NavBar.prototype, "hr_attendance_custom_form.systray_items_patch", { + get systrayItems() { + const menuItems = this._super(...arguments); console.log("Original systrayItems:", menuItems); if (!Array.isArray(menuItems)) { - console.warn("systrayItems is not an array or is undefined:", menuItems); - return []; + console.warn("systrayItems is not an array or is undefined:", menuItems); + return []; } - const filteredItems = menuItems.filter(item => item.key === "web.user_menu"); + const filteredItems = menuItems.filter((item) => item.key === "web.user_menu"); console.log("Filtered systrayItems (web.user_menu):", filteredItems); return filteredItems; - } -}); \ No newline at end of file + }, + }); + } +); diff --git a/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml index a36fa69e..68fce366 100644 --- a/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml +++ b/hr_attendance_custom_form/static/src/xml/hr_attendance_custom_remove.xml @@ -1,20 +1,28 @@ - + - +
-