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 <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-31 22:47:12 -04:00
parent 914c96a09a
commit 2ab59bccde
3 changed files with 48 additions and 11 deletions

View File

@@ -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': """

View File

@@ -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

View File

@@ -19,11 +19,11 @@
<div class="content-group">
<div class="row mt16">
<label for="fclk_default_clock_in_time" string="Clock-In" class="col-lg-5 o_light_label"/>
<field name="fclk_default_clock_in_time" widget="float_time"/>
<field name="fclk_default_clock_in_time"/>
</div>
<div class="row mt8">
<label for="fclk_default_clock_out_time" string="Clock-Out" class="col-lg-5 o_light_label"/>
<field name="fclk_default_clock_out_time" widget="float_time"/>
<field name="fclk_default_clock_out_time"/>
</div>
</div>
</setting>