feat(fusion_clock): NFC kiosk attendance fields + activity-log selections
- Add 'nfc_kiosk' to x_fclk_clock_source selection on hr.attendance - Add x_fclk_check_in_photo and x_fclk_check_out_photo Binary fields (attachment=True) - Add 'card_enrollment' and 'unknown_card_tap' to activity log log_type selection - Add 'nfc_kiosk' to activity log source selection - Add TestNfcAttendanceFields test class (3 tests); all 6 fusion_clock tests pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,8 @@ class FusionClockActivityLog(models.Model):
|
||||
('correction_request', 'Correction Request'),
|
||||
('ip_fallback', 'IP Fallback Used'),
|
||||
('streak_milestone', 'Streak Milestone'),
|
||||
('card_enrollment', 'Card Enrollment'),
|
||||
('unknown_card_tap', 'Unknown Card Tap'),
|
||||
],
|
||||
string='Log Type',
|
||||
required=True,
|
||||
@@ -72,6 +74,7 @@ class FusionClockActivityLog(models.Model):
|
||||
('backend_fab', 'Backend FAB'),
|
||||
('kiosk', 'Kiosk'),
|
||||
('system', 'System (Cron)'),
|
||||
('nfc_kiosk', 'NFC Kiosk'),
|
||||
],
|
||||
string='Source',
|
||||
)
|
||||
|
||||
@@ -130,6 +130,7 @@ class HrAttendance(models.Model):
|
||||
('systray', 'Systray'),
|
||||
('backend_fab', 'Backend FAB'),
|
||||
('kiosk', 'Kiosk'),
|
||||
('nfc_kiosk', 'NFC Kiosk'),
|
||||
('manual', 'Manual'),
|
||||
('auto', 'Auto Clock-Out'),
|
||||
],
|
||||
@@ -147,6 +148,16 @@ class HrAttendance(models.Model):
|
||||
digits=(10, 2),
|
||||
help="Distance from location center at clock-out, in meters.",
|
||||
)
|
||||
x_fclk_check_in_photo = fields.Binary(
|
||||
string='Check-In Photo',
|
||||
attachment=True,
|
||||
help="Front-camera photo captured at NFC kiosk clock-in.",
|
||||
)
|
||||
x_fclk_check_out_photo = fields.Binary(
|
||||
string='Check-Out Photo',
|
||||
attachment=True,
|
||||
help="Front-camera photo captured at NFC kiosk clock-out.",
|
||||
)
|
||||
x_fclk_break_minutes = fields.Float(
|
||||
string='Break (min)',
|
||||
default=0.0,
|
||||
|
||||
@@ -31,3 +31,54 @@ class TestNfcModels(TransactionCase):
|
||||
self.bob.x_fclk_nfc_card_uid = False
|
||||
self.assertFalse(self.alice.x_fclk_nfc_card_uid)
|
||||
self.assertFalse(self.bob.x_fclk_nfc_card_uid)
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install', 'fusion_clock')
|
||||
class TestNfcAttendanceFields(TransactionCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.employee = cls.env['hr.employee'].create({
|
||||
'name': 'NFC Test Employee',
|
||||
'x_fclk_enable_clock': True,
|
||||
})
|
||||
|
||||
def test_clock_source_includes_nfc_kiosk(self):
|
||||
attendance = self.env['hr.attendance'].create({
|
||||
'employee_id': self.employee.id,
|
||||
'check_in': '2026-05-13 08:00:00',
|
||||
'x_fclk_clock_source': 'nfc_kiosk',
|
||||
})
|
||||
self.assertEqual(attendance.x_fclk_clock_source, 'nfc_kiosk')
|
||||
|
||||
def test_photo_fields_accept_binary(self):
|
||||
# 1x1 transparent PNG as base64
|
||||
png_b64 = (
|
||||
b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAA'
|
||||
b'C0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='
|
||||
)
|
||||
attendance = self.env['hr.attendance'].create({
|
||||
'employee_id': self.employee.id,
|
||||
'check_in': '2026-05-13 08:00:00',
|
||||
'x_fclk_check_in_photo': png_b64,
|
||||
})
|
||||
self.assertTrue(attendance.x_fclk_check_in_photo)
|
||||
|
||||
def test_activity_log_accepts_new_selections(self):
|
||||
log = self.env['fusion.clock.activity.log'].create({
|
||||
'employee_id': self.employee.id,
|
||||
'log_type': 'card_enrollment',
|
||||
'source': 'nfc_kiosk',
|
||||
'description': 'Test enrollment log',
|
||||
})
|
||||
self.assertEqual(log.log_type, 'card_enrollment')
|
||||
self.assertEqual(log.source, 'nfc_kiosk')
|
||||
|
||||
log2 = self.env['fusion.clock.activity.log'].create({
|
||||
'employee_id': self.employee.id,
|
||||
'log_type': 'unknown_card_tap',
|
||||
'source': 'nfc_kiosk',
|
||||
'description': 'Test unknown card log',
|
||||
})
|
||||
self.assertEqual(log2.log_type, 'unknown_card_tap')
|
||||
|
||||
Reference in New Issue
Block a user