import json import logging from odoo import api, fields, models, tools from odoo.exceptions import ValidationError _logger = logging.getLogger(__name__) class AttendanceIot(models.Model): _name = 'attendance.iot' _description = '考勤机设备' _rec_name = 'display_name' name = fields.Char(string="设备号") display_name = fields.Char(string="名称", compute='_compute_display_name', store=True) attendance_address = fields.Char(string="设备地址") broker = fields.Char(string='服务器地址/ip') port = fields.Char(string='端口号') number = fields.Integer(string="数量", compute="compute_iot_num") id_valid = fields.Datetime(string="设备有效期") company_id = fields.Many2one('res.company', string="公司") remake = fields.Text(string='备注') employee_ids = fields.Many2many('hr.employee', string="员工") is_connected = fields.Boolean(string="连接状态", default=False) last_update_time = fields.Datetime(string="最后更新时间") @api.depends('company_id', 'attendance_address', 'name') def _compute_display_name(self): for r in self: parts = [] if r.company_id: parts.append(r.company_id.name) if r.attendance_address: parts.append(r.attendance_address) if r.name: parts.append(r.name) r.display_name = ' - '.join(parts) if parts else r.name or '' def action_init_device(self): ''' 初始化设备数据 ''' # 查找 员工 values = [] upload_records = self.env['attendance.iot.user'] for record in self: employees = self.env['hr.employee'].search([('company_id', '=', record.company_id.id)]) # employee_list = [emp.name for emp in employees] # _logger.info(f"{employee_list}") for employee in employees: iot_user = self.env['attendance.iot.user'].search([('attendance_iot_id', '=', record.id), ('employee_id', '=', employee.id)]) if iot_user: upload_records += iot_user continue values.append({ 'employee_id': employee.id, 'attendance_iot_id': record.id }) _logger.info(f"{employee.name}") # 没有的创建 self.env['attendance.iot.user'].create(values) # 有记录的更新 upload_records.action_update_iot_info() def open_record(self): self.ensure_one() return { 'name': '设备关联用户', 'type': 'ir.actions.act_window', 'res_model': 'attendance.iot.user', 'view_mode': 'tree', 'domain': [('attendance_iot_id', '=', self.id)], 'context': {'default_attendance_iot_id': self.id} } def compute_iot_num(self): for num in self: num.number = len(self.env['attendance.iot.user'].search([('attendance_iot_id', '=', num.id)])) def action_send_sync_sigle(self): ''' 向设备发送数据同步信号 ''' for record in self: self.env['iot.message'].create([{ 'name': '增加用户', 'topic': f'iot/device/{record.name}', 'device_sn': record.name, 'message_data': json.dumps({ 'cmd': 'uploadFaceInfo' }, ensure_ascii=False) }]) # 发送开门信号 def action_send_open_door_sigle(self): for record in self: msg = { 'cmd': 'setDoor', 'value': 'on' } msg.pop('face_template', None) self.env['iot.message'].create([{ 'name': '开门', 'topic': f'iot/device/{record.name}', 'device_sn': record.name, 'message_data': json.dumps(msg, ensure_ascii=False) }]) def action_send_close_door_sigle(self): for record in self: msg = { 'cmd': 'setDoor', 'value': 'off' } msg.pop('face_template', None) self.env['iot.message'].create([{ 'name': '开门', 'topic': f'iot/device/{record.name}', 'device_sn': record.name, 'message_data': json.dumps(msg, ensure_ascii=False) }]) def action_view_logs(self): """查看该设备的 MQTT 操作日志(开门/关门/下发/同步)""" self.ensure_one() return { 'name': '考勤机日志', 'type': 'ir.actions.act_window', 'res_model': 'iot.message', 'view_mode': 'tree,form', 'domain': [('device_sn', '=', self.name)], } def touch_last_update(self): """更新最后触发时间(MQTT/API 每次触发时调用)""" self.write({'last_update_time': fields.Datetime.now()}) def _log(self, event_type, content): """写入设备操作日志到 iot.message""" self.ensure_one() self.env['iot.message'].create({ 'name': event_type, 'device_sn': self.name, 'topic': f'iot/device/{self.name}', 'message_data': content, 'state': 'done', })