summaryrefslogtreecommitdiff
path: root/addons/hr_attendance/static/src/js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/hr_attendance/static/src/js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/hr_attendance/static/src/js')
-rw-r--r--addons/hr_attendance/static/src/js/employee_kanban_view_handler.js35
-rw-r--r--addons/hr_attendance/static/src/js/greeting_message.js182
-rw-r--r--addons/hr_attendance/static/src/js/kiosk_confirm.js94
-rw-r--r--addons/hr_attendance/static/src/js/kiosk_mode.js85
-rw-r--r--addons/hr_attendance/static/src/js/my_attendances.js56
-rw-r--r--addons/hr_attendance/static/src/js/time_widget.js19
6 files changed, 471 insertions, 0 deletions
diff --git a/addons/hr_attendance/static/src/js/employee_kanban_view_handler.js b/addons/hr_attendance/static/src/js/employee_kanban_view_handler.js
new file mode 100644
index 00000000..02801f79
--- /dev/null
+++ b/addons/hr_attendance/static/src/js/employee_kanban_view_handler.js
@@ -0,0 +1,35 @@
+
+odoo.define('hr_attendance.employee_kanban_view_handler', function(require) {
+"use strict";
+
+var KanbanRecord = require('web.KanbanRecord');
+
+KanbanRecord.include({
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ * @private
+ */
+ _openRecord: function () {
+ if (this.modelName === 'hr.employee.public' && this.$el.parents('.o_hr_employee_attendance_kanban').length) {
+ // needed to diffentiate : check in/out kanban view of employees <-> standard employee kanban view
+ var action = {
+ type: 'ir.actions.client',
+ name: 'Confirm',
+ tag: 'hr_attendance_kiosk_confirm',
+ employee_id: this.record.id.raw_value,
+ employee_name: this.record.name.raw_value,
+ employee_state: this.record.attendance_state.raw_value,
+ employee_hours_today: this.record.hours_today.raw_value,
+ };
+ this.do_action(action);
+ } else {
+ this._super.apply(this, arguments);
+ }
+ }
+});
+
+});
diff --git a/addons/hr_attendance/static/src/js/greeting_message.js b/addons/hr_attendance/static/src/js/greeting_message.js
new file mode 100644
index 00000000..101f6dae
--- /dev/null
+++ b/addons/hr_attendance/static/src/js/greeting_message.js
@@ -0,0 +1,182 @@
+odoo.define('hr_attendance.greeting_message', function (require) {
+"use strict";
+
+var AbstractAction = require('web.AbstractAction');
+var core = require('web.core');
+var time = require('web.time');
+
+var _t = core._t;
+
+
+var GreetingMessage = AbstractAction.extend({
+ contentTemplate: 'HrAttendanceGreetingMessage',
+
+ events: {
+ "click .o_hr_attendance_button_dismiss": function() { this.do_action(this.next_action, {clear_breadcrumbs: true}); },
+ },
+
+ init: function(parent, action) {
+ var self = this;
+ this._super.apply(this, arguments);
+ this.activeBarcode = true;
+
+ // if no correct action given (due to an erroneous back or refresh from the browser), we set the dismiss button to return
+ // to the (likely) appropriate menu, according to the user access rights
+ if(!action.attendance) {
+ this.activeBarcode = false;
+ this.getSession().user_has_group('hr_attendance.group_hr_attendance_user').then(function(has_group) {
+ if(has_group) {
+ self.next_action = 'hr_attendance.hr_attendance_action_kiosk_mode';
+ } else {
+ self.next_action = 'hr_attendance.hr_attendance_action_my_attendances';
+ }
+ });
+ return;
+ }
+
+ this.next_action = action.next_action || 'hr_attendance.hr_attendance_action_my_attendances';
+ // no listening to barcode scans if we aren't coming from the kiosk mode (and thus not going back to it with next_action)
+ if (this.next_action != 'hr_attendance.hr_attendance_action_kiosk_mode' && this.next_action.tag != 'hr_attendance_kiosk_mode') {
+ this.activeBarcode = false;
+ }
+
+ this.attendance = action.attendance;
+ // We receive the check in/out times in UTC
+ // This widget only deals with display, which should be in browser's TimeZone
+ this.attendance.check_in = this.attendance.check_in && moment.utc(this.attendance.check_in).local();
+ this.attendance.check_out = this.attendance.check_out && moment.utc(this.attendance.check_out).local();
+ this.previous_attendance_change_date = action.previous_attendance_change_date && moment.utc(action.previous_attendance_change_date).local();
+
+ // check in/out times displayed in the greeting message template.
+ this.format_time = time.getLangTimeFormat();
+ this.attendance.check_in_time = this.attendance.check_in && this.attendance.check_in.format(this.format_time);
+ this.attendance.check_out_time = this.attendance.check_out && this.attendance.check_out.format(this.format_time);
+
+ if (action.hours_today) {
+ var duration = moment.duration(action.hours_today, "hours");
+ this.hours_today = duration.hours() + ' hours, ' + duration.minutes() + ' minutes';
+ }
+
+ this.employee_name = action.employee_name;
+ this.attendanceBarcode = action.barcode;
+ },
+
+ start: function() {
+ if (this.attendance) {
+ this.attendance.check_out ? this.farewell_message() : this.welcome_message();
+ }
+ if (this.activeBarcode) {
+ core.bus.on('barcode_scanned', this, this._onBarcodeScanned);
+ }
+ return this._super.apply(this, arguments);
+ },
+
+ welcome_message: function() {
+ var self = this;
+ var now = this.attendance.check_in.clone();
+ this.return_to_main_menu = setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
+
+ if (now.hours() < 5) {
+ this.$('.o_hr_attendance_message_message').append(_t("Good night"));
+ } else if (now.hours() < 12) {
+ if (now.hours() < 8 && Math.random() < 0.3) {
+ if (Math.random() < 0.75) {
+ this.$('.o_hr_attendance_message_message').append(_t("The early bird catches the worm"));
+ } else {
+ this.$('.o_hr_attendance_message_message').append(_t("First come, first served"));
+ }
+ } else {
+ this.$('.o_hr_attendance_message_message').append(_t("Good morning"));
+ }
+ } else if (now.hours() < 17){
+ this.$('.o_hr_attendance_message_message').append(_t("Good afternoon"));
+ } else if (now.hours() < 23){
+ this.$('.o_hr_attendance_message_message').append(_t("Good evening"));
+ } else {
+ this.$('.o_hr_attendance_message_message').append(_t("Good night"));
+ }
+ if(this.previous_attendance_change_date){
+ var last_check_out_date = this.previous_attendance_change_date.clone();
+ if(now - last_check_out_date > 24*7*60*60*1000){
+ this.$('.o_hr_attendance_random_message').html(_t("Glad to have you back, it's been a while!"));
+ } else {
+ if(Math.random() < 0.02){
+ this.$('.o_hr_attendance_random_message').html(_t("If a job is worth doing, it is worth doing well!"));
+ }
+ }
+ }
+ },
+
+ farewell_message: function() {
+ var self = this;
+ var now = this.attendance.check_out.clone();
+ this.return_to_main_menu = setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
+
+ if(this.previous_attendance_change_date){
+ var last_check_in_date = this.previous_attendance_change_date.clone();
+ if(now - last_check_in_date > 1000*60*60*12){
+ this.$('.o_hr_attendance_warning_message').show().append(_t("<b>Warning! Last check in was over 12 hours ago.</b><br/>If this isn't right, please contact Human Resource staff"));
+ clearTimeout(this.return_to_main_menu);
+ this.activeBarcode = false;
+ } else if(now - last_check_in_date > 1000*60*60*8){
+ this.$('.o_hr_attendance_random_message').html(_t("Another good day's work! See you soon!"));
+ }
+ }
+
+ if (now.hours() < 12) {
+ this.$('.o_hr_attendance_message_message').append(_t("Have a good day!"));
+ } else if (now.hours() < 14) {
+ this.$('.o_hr_attendance_message_message').append(_t("Have a nice lunch!"));
+ if (Math.random() < 0.05) {
+ this.$('.o_hr_attendance_random_message').html(_t("Eat breakfast as a king, lunch as a merchant and supper as a beggar"));
+ } else if (Math.random() < 0.06) {
+ this.$('.o_hr_attendance_random_message').html(_t("An apple a day keeps the doctor away"));
+ }
+ } else if (now.hours() < 17) {
+ this.$('.o_hr_attendance_message_message').append(_t("Have a good afternoon"));
+ } else {
+ if (now.hours() < 18 && Math.random() < 0.2) {
+ this.$('.o_hr_attendance_message_message').append(_t("Early to bed and early to rise, makes a man healthy, wealthy and wise"));
+ } else {
+ this.$('.o_hr_attendance_message_message').append(_t("Have a good evening"));
+ }
+ }
+ },
+
+ _onBarcodeScanned: function(barcode) {
+ var self = this;
+ if (this.attendanceBarcode !== barcode){
+ if (this.return_to_main_menu) { // in case of multiple scans in the greeting message view, delete the timer, a new one will be created.
+ clearTimeout(this.return_to_main_menu);
+ }
+ core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
+ this._rpc({
+ model: 'hr.employee',
+ method: 'attendance_scan',
+ args: [barcode, ],
+ })
+ .then(function (result) {
+ if (result.action) {
+ self.do_action(result.action);
+ } else if (result.warning) {
+ self.do_warn(result.warning);
+ setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
+ }
+ }, function () {
+ setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
+ });
+ }
+ },
+
+ destroy: function () {
+ core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
+ clearTimeout(this.return_to_main_menu);
+ this._super.apply(this, arguments);
+ },
+});
+
+core.action_registry.add('hr_attendance_greeting_message', GreetingMessage);
+
+return GreetingMessage;
+
+});
diff --git a/addons/hr_attendance/static/src/js/kiosk_confirm.js b/addons/hr_attendance/static/src/js/kiosk_confirm.js
new file mode 100644
index 00000000..8262b24c
--- /dev/null
+++ b/addons/hr_attendance/static/src/js/kiosk_confirm.js
@@ -0,0 +1,94 @@
+odoo.define('hr_attendance.kiosk_confirm', function (require) {
+"use strict";
+
+var AbstractAction = require('web.AbstractAction');
+var core = require('web.core');
+var field_utils = require('web.field_utils');
+var QWeb = core.qweb;
+
+
+var KioskConfirm = AbstractAction.extend({
+ events: {
+ "click .o_hr_attendance_back_button": function () { this.do_action(this.next_action, {clear_breadcrumbs: true}); },
+ "click .o_hr_attendance_sign_in_out_icon": _.debounce(function () {
+ var self = this;
+ this._rpc({
+ model: 'hr.employee',
+ method: 'attendance_manual',
+ args: [[this.employee_id], this.next_action],
+ })
+ .then(function(result) {
+ if (result.action) {
+ self.do_action(result.action);
+ } else if (result.warning) {
+ self.do_warn(result.warning);
+ }
+ });
+ }, 200, true),
+ 'click .o_hr_attendance_pin_pad_button_0': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 0); },
+ 'click .o_hr_attendance_pin_pad_button_1': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 1); },
+ 'click .o_hr_attendance_pin_pad_button_2': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 2); },
+ 'click .o_hr_attendance_pin_pad_button_3': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 3); },
+ 'click .o_hr_attendance_pin_pad_button_4': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 4); },
+ 'click .o_hr_attendance_pin_pad_button_5': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 5); },
+ 'click .o_hr_attendance_pin_pad_button_6': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 6); },
+ 'click .o_hr_attendance_pin_pad_button_7': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 7); },
+ 'click .o_hr_attendance_pin_pad_button_8': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 8); },
+ 'click .o_hr_attendance_pin_pad_button_9': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 9); },
+ 'click .o_hr_attendance_pin_pad_button_C': function() { this.$('.o_hr_attendance_PINbox').val(''); },
+ 'click .o_hr_attendance_pin_pad_button_ok': _.debounce(function() {
+ var self = this;
+ this.$('.o_hr_attendance_pin_pad_button_ok').attr("disabled", "disabled");
+ this._rpc({
+ model: 'hr.employee',
+ method: 'attendance_manual',
+ args: [[this.employee_id], this.next_action, this.$('.o_hr_attendance_PINbox').val()],
+ })
+ .then(function(result) {
+ if (result.action) {
+ self.do_action(result.action);
+ } else if (result.warning) {
+ self.do_warn(result.warning);
+ self.$('.o_hr_attendance_PINbox').val('');
+ setTimeout( function() { self.$('.o_hr_attendance_pin_pad_button_ok').removeAttr("disabled"); }, 500);
+ }
+ });
+ }, 200, true),
+ },
+
+ init: function (parent, action) {
+ this._super.apply(this, arguments);
+ this.next_action = 'hr_attendance.hr_attendance_action_kiosk_mode';
+ this.employee_id = action.employee_id;
+ this.employee_name = action.employee_name;
+ this.employee_state = action.employee_state;
+ this.employee_hours_today = field_utils.format.float_time(action.employee_hours_today);
+ },
+
+ start: function () {
+ var self = this;
+ this.getSession().user_has_group('hr_attendance.group_hr_attendance_use_pin').then(function(has_group){
+ self.use_pin = has_group;
+ self.$el.html(QWeb.render("HrAttendanceKioskConfirm", {widget: self}));
+ self.start_clock();
+ });
+ return self._super.apply(this, arguments);
+ },
+
+ start_clock: function () {
+ this.clock_start = setInterval(function() {this.$(".o_hr_attendance_clock").text(new Date().toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit', second:'2-digit'}));}, 500);
+ // First clock refresh before interval to avoid delay
+ this.$(".o_hr_attendance_clock").show().text(new Date().toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit', second:'2-digit'}));
+ },
+
+ destroy: function () {
+ clearInterval(this.clock_start);
+ this._super.apply(this, arguments);
+ },
+});
+
+core.action_registry.add('hr_attendance_kiosk_confirm', KioskConfirm);
+
+return KioskConfirm;
+
+});
diff --git a/addons/hr_attendance/static/src/js/kiosk_mode.js b/addons/hr_attendance/static/src/js/kiosk_mode.js
new file mode 100644
index 00000000..6ce0c026
--- /dev/null
+++ b/addons/hr_attendance/static/src/js/kiosk_mode.js
@@ -0,0 +1,85 @@
+odoo.define('hr_attendance.kiosk_mode', function (require) {
+"use strict";
+
+var AbstractAction = require('web.AbstractAction');
+var ajax = require('web.ajax');
+var core = require('web.core');
+var Session = require('web.session');
+
+var QWeb = core.qweb;
+
+
+var KioskMode = AbstractAction.extend({
+ events: {
+ "click .o_hr_attendance_button_employees": function() {
+ this.do_action('hr_attendance.hr_employee_attendance_action_kanban', {
+ additional_context: {'no_group_by': true},
+ });
+ },
+ },
+
+ start: function () {
+ var self = this;
+ core.bus.on('barcode_scanned', this, this._onBarcodeScanned);
+ self.session = Session;
+ var def = this._rpc({
+ model: 'res.company',
+ method: 'search_read',
+ args: [[['id', '=', this.session.company_id]], ['name']],
+ })
+ .then(function (companies){
+ self.company_name = companies[0].name;
+ self.company_image_url = self.session.url('/web/image', {model: 'res.company', id: self.session.company_id, field: 'logo',});
+ self.$el.html(QWeb.render("HrAttendanceKioskMode", {widget: self}));
+ self.start_clock();
+ });
+ // Make a RPC call every day to keep the session alive
+ self._interval = window.setInterval(this._callServer.bind(this), (60*60*1000*24));
+ return Promise.all([def, this._super.apply(this, arguments)]);
+ },
+
+ _onBarcodeScanned: function(barcode) {
+ var self = this;
+ core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
+ this._rpc({
+ model: 'hr.employee',
+ method: 'attendance_scan',
+ args: [barcode, ],
+ })
+ .then(function (result) {
+ if (result.action) {
+ self.do_action(result.action);
+ } else if (result.warning) {
+ self.do_warn(result.warning);
+ core.bus.on('barcode_scanned', self, self._onBarcodeScanned);
+ }
+ }, function () {
+ core.bus.on('barcode_scanned', self, self._onBarcodeScanned);
+ });
+ },
+
+ start_clock: function() {
+ this.clock_start = setInterval(function() {this.$(".o_hr_attendance_clock").text(new Date().toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit', second:'2-digit'}));}, 500);
+ // First clock refresh before interval to avoid delay
+ this.$(".o_hr_attendance_clock").show().text(new Date().toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit', second:'2-digit'}));
+ },
+
+ destroy: function () {
+ core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
+ clearInterval(this.clock_start);
+ clearInterval(this._interval);
+ this._super.apply(this, arguments);
+ },
+
+ _callServer: function () {
+ // Make a call to the database to avoid the auto close of the session
+ return ajax.rpc("/hr_attendance/kiosk_keepalive", {});
+ },
+
+});
+
+core.action_registry.add('hr_attendance_kiosk_mode', KioskMode);
+
+return KioskMode;
+
+});
diff --git a/addons/hr_attendance/static/src/js/my_attendances.js b/addons/hr_attendance/static/src/js/my_attendances.js
new file mode 100644
index 00000000..91acb7f1
--- /dev/null
+++ b/addons/hr_attendance/static/src/js/my_attendances.js
@@ -0,0 +1,56 @@
+odoo.define('hr_attendance.my_attendances', function (require) {
+"use strict";
+
+var AbstractAction = require('web.AbstractAction');
+var core = require('web.core');
+var field_utils = require('web.field_utils');
+
+
+var MyAttendances = AbstractAction.extend({
+ contentTemplate: 'HrAttendanceMyMainMenu',
+ events: {
+ "click .o_hr_attendance_sign_in_out_icon": _.debounce(function() {
+ this.update_attendance();
+ }, 200, true),
+ },
+
+ willStart: function () {
+ var self = this;
+
+ var def = this._rpc({
+ model: 'hr.employee',
+ method: 'search_read',
+ args: [[['user_id', '=', this.getSession().uid]], ['attendance_state', 'name', 'hours_today']],
+ })
+ .then(function (res) {
+ self.employee = res.length && res[0];
+ if (res.length) {
+ self.hours_today = field_utils.format.float_time(self.employee.hours_today);
+ }
+ });
+
+ return Promise.all([def, this._super.apply(this, arguments)]);
+ },
+
+ update_attendance: function () {
+ var self = this;
+ this._rpc({
+ model: 'hr.employee',
+ method: 'attendance_manual',
+ args: [[self.employee.id], 'hr_attendance.hr_attendance_action_my_attendances'],
+ })
+ .then(function(result) {
+ if (result.action) {
+ self.do_action(result.action);
+ } else if (result.warning) {
+ self.do_warn(result.warning);
+ }
+ });
+ },
+});
+
+core.action_registry.add('hr_attendance_my_attendances', MyAttendances);
+
+return MyAttendances;
+
+});
diff --git a/addons/hr_attendance/static/src/js/time_widget.js b/addons/hr_attendance/static/src/js/time_widget.js
new file mode 100644
index 00000000..eabfcfbb
--- /dev/null
+++ b/addons/hr_attendance/static/src/js/time_widget.js
@@ -0,0 +1,19 @@
+odoo.define('hr_attendance.widget', function (require) {
+ "use strict";
+
+ var basic_fields = require('web.basic_fields');
+ var field_registry = require('web.field_registry');
+
+ var RelativeTime = basic_fields.FieldDateTime.extend({
+ _formatValue: function (val) {
+ if (!(val && val._isAMomentObject)) {
+ return;
+ }
+ return val.fromNow(true);
+ },
+ });
+
+ field_registry.add('relative_time', RelativeTime);
+
+ return RelativeTime;
+}); \ No newline at end of file