From 2ab59bccdeabafe6d4452bdef9ef8f8c34e7fd46 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sun, 31 May 2026 22:47:12 -0400 Subject: [PATCH] feat(fusion_clock): default clock-in/out times as 12-hour AM/PM dropdowns People aren't good with 24h. Default Clock-In/Out are now AM/PM dropdowns (15-min grid) instead of 24h float_time inputs. Stored value stays the float-string (e.g. '9.0'), so all downstream float(get_param(...)) reads are unchanged; persisted manually with get-snap for any off-grid value. Bump 19.0.4.0.3. Co-Authored-By: Claude Opus 4.8 --- fusion_clock/__manifest__.py | 2 +- fusion_clock/models/res_config_settings.py | 53 ++++++++++++++++--- .../views/res_config_settings_views.xml | 4 +- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/fusion_clock/__manifest__.py b/fusion_clock/__manifest__.py index 62b3b8e7..f2ed0b42 100644 --- a/fusion_clock/__manifest__.py +++ b/fusion_clock/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Clock', - 'version': '19.0.4.0.2', + 'version': '19.0.4.0.3', 'category': 'Human Resources/Attendances', 'summary': 'Complete Employee T&A with Geofencing, Shifts, Penalties, Overtime, Kiosk, Dashboard & Payroll Export', 'description': """ diff --git a/fusion_clock/models/res_config_settings.py b/fusion_clock/models/res_config_settings.py index c8f9e7c3..9da8a313 100644 --- a/fusion_clock/models/res_config_settings.py +++ b/fusion_clock/models/res_config_settings.py @@ -9,17 +9,21 @@ class ResConfigSettings(models.TransientModel): _inherit = 'res.config.settings' # ── Work Schedule ────────────────────────────────────────────────── - fclk_default_clock_in_time = fields.Float( + # 12-hour AM/PM dropdowns (people aren't good with 24h). The selection VALUE + # is the float-as-string the backend stores (e.g. '9.0', '17.5'), so all + # downstream float(get_param(...)) reads are unchanged. Persisted manually in + # get_values/set_values (a 15-min grid; get snaps any off-grid stored value). + fclk_default_clock_in_time = fields.Selection( + selection='_fclk_time_selection', string='Default Clock-In Time', - config_parameter='fusion_clock.default_clock_in_time', - default=9.0, - help="Default scheduled clock-in time (24h format, e.g. 9.0 = 9:00 AM).", + default='9.0', + help="Default scheduled clock-in time, used when no shift is assigned.", ) - fclk_default_clock_out_time = fields.Float( + fclk_default_clock_out_time = fields.Selection( + selection='_fclk_time_selection', string='Default Clock-Out Time', - config_parameter='fusion_clock.default_clock_out_time', - default=17.0, - help="Default scheduled clock-out time (24h format, e.g. 17.0 = 5:00 PM).", + default='17.0', + help="Default scheduled clock-out time, used when no shift is assigned.", ) fclk_auto_deduct_break = fields.Boolean( string='Auto-Deduct Break', @@ -280,11 +284,40 @@ class ResConfigSettings(models.TransientModel): ('fclk_nfc_kiosk_debug', 'fusion_clock.nfc_kiosk_debug', False), ] + @api.model + def _fclk_time_selection(self): + """15-minute grid of 12-hour clock times. Each option's VALUE is the + float-as-string the backend stores (e.g. '9.0', '17.5'); the LABEL is + the friendly 12-hour form (e.g. '9:00 AM').""" + opts = [] + for i in range(96): + f = i * 0.25 + h24 = int(f) + mm = int(round((f - h24) * 60)) + ap = 'AM' if h24 < 12 else 'PM' + h12 = h24 % 12 or 12 + opts.append((str(f), '%d:%02d %s' % (h12, mm, ap))) + return opts + + @staticmethod + def _fclk_snap_time(value, default_float): + """Snap a stored float-ish time to the nearest 15-min grid key string.""" + try: + f = float(value) + except (ValueError, TypeError): + f = default_float + f = round(f * 4) / 4 + if f < 0 or f >= 24: + f = default_float + return str(f) + def set_values(self): super().set_values() ICP = self.env['ir.config_parameter'].sudo() for fname, key, _default in self._FCLK_BOOL_PARAMS: ICP.set_param(key, 'True' if self[fname] else 'False') + ICP.set_param('fusion_clock.default_clock_in_time', self.fclk_default_clock_in_time or '9.0') + ICP.set_param('fusion_clock.default_clock_out_time', self.fclk_default_clock_out_time or '17.0') if self.fclk_office_user_id: ICP.set_param('fusion_clock.office_user_id', str(self.fclk_office_user_id.id)) else: @@ -323,4 +356,8 @@ class ResConfigSettings(models.TransientModel): res['fclk_pay_period_start'] = fields.Date.to_date(anchor_str[:10]) except (ValueError, TypeError): pass + res['fclk_default_clock_in_time'] = self._fclk_snap_time( + ICP.get_param('fusion_clock.default_clock_in_time', '9.0'), 9.0) + res['fclk_default_clock_out_time'] = self._fclk_snap_time( + ICP.get_param('fusion_clock.default_clock_out_time', '17.0'), 17.0) return res diff --git a/fusion_clock/views/res_config_settings_views.xml b/fusion_clock/views/res_config_settings_views.xml index 4682f2d6..e5a7a2a1 100644 --- a/fusion_clock/views/res_config_settings_views.xml +++ b/fusion_clock/views/res_config_settings_views.xml @@ -19,11 +19,11 @@