Merge pull request !3090 from 李鹏宇/dev
This commit is contained in:
李鹏宇
2025-06-04 14:00:53 +00:00
committed by Gitee
21 changed files with 130 additions and 86 deletions
+1
View File
@@ -14,6 +14,7 @@
'data': [
'security/ir.model.access.csv',
'views/attendance_iot_datas.xml',
'views/attendance_iot_user_views.xml',
'views/attendance_iot_manager_views.xml',
'views/attendance_iot_views.xml',
'views/inherit_hr_employee_views.xml',
+30 -63
View File
@@ -1,54 +1,11 @@
from venv import create
from odoo.http import Controller, request, route
from datetime import datetime
from odoo import models, fields, api, http, SUPERUSER_ID, _
class BusController(Controller):
def get_equipment_company(self, sn):
sn_address = {
'RLM-00111018': '地址1',
}
return sn_address[sn]
@route('/api/v1/record/face', methods=['POST'], type='json', auth='none', csrf=False)
def get_model_definitions(self):
"""
用户通过考勤机识别,写入考勤数据
:return:
"""
data = request.httprequest.json['logs'][0]
user_name = data.get('user_name')
employee_id = request.env(user=SUPERUSER_ID)["hr.employee"].search([('name', '=', user_name)])
request.env(user=SUPERUSER_ID)["hr.attendance"].create({
'employee_id': employee_id.id,
'check_in': datetime.strptime(data.get('recog_time'), '%Y-%m-%d %H:%M:%S')
})
print("---------------------------------------------测试成功---------------------------------------")
return {"Result": 0, "Msg": "添加成功"}
@route('/api/v1/user/inf_photo', methods=['POST'], type='json', auth='public')
def get_model_definitions(self):
name = request.jsonrequest.get('sn') # 姓名
phone = request.jsonrequest.get('content') # 电话
print(name, phone)
return {
"Result": 0,
"Msg": "更新成功"
}
# 员工识别接口
@route('/api/v1/stranger', methods=['POST'], type='json', auth='none')
def get_model_definitions(self):
data = request.httprequest.json.get('logs')[0]
user_name = data['user_name']
request.env["hr.employee"].create({
'name': user_name + 'stranger',
})
print("---------------------------------------------测试成功---------------------------------------")
return {
"Result": 0,
"Msg": "更新成功"
}
@route('/api/v1/addFace', methods=['POST'], type='json', auth='none', csrf=False)
def get_model_kaoqin(self):
@@ -58,19 +15,26 @@ class BusController(Controller):
"""
data = request.httprequest.json
user_name = data.get('name')
name = data.get('sn')
# validity_period = datetime.strptime(data.get('validity_period'), '%Y-%m-%d').date()
employee_id = request.env(user=SUPERUSER_ID)["hr.employee"].search([('name', '=', user_name)])
attendance_iot = request.env(user=SUPERUSER_ID)["attendance.iot.manager"]
if not attendance_iot.search([('employee_id', '=', employee_id.id), ('attendance_number', '=', data.get('sn'))]):
employee_id.write({
attendance_iot_id = request.env["attendance.iot"].search([('name', '=', name)])
if not attendance_iot_id:
request.env["attendance.iot"].create({
'name': name,
})
employee = request.env(user=SUPERUSER_ID)["hr.employee"].search([('name', '=', user_name)])
# 判断员工是否绑定多台设备
if employee and attendance_iot_id not in employee.attendance_iot_ids.mapped('attendance_iot_id'):
employee.write({
'image_1920': data.get('photo'),
'attendance_iot_ids': [(0, 0, {
'employee_id': employee.id,
'attendance_address': self.get_equipment_company(data.get('sn')),
'attendance_iot_id': attendance_iot_id.id
})]
})
attendance_iot.create({
'data_selection': "api",
'attendance_number': data.get('sn'),
'attendance_address': self.get_equipment_company(data.get('sn')),
'employee_id': employee_id.id,
})
print("---------------------------------------------测试成功---------------------------------------")
return {"Result": 0, "Msg": "添加成功"}
@@ -81,15 +45,18 @@ class BusController(Controller):
:return:
"""
data = request.httprequest.json
user_name = data.get('logs').get('user_id')
employee_id = request.env(user=SUPERUSER_ID)["hr.employee"].search([('user_id', '=', user_name.id)])
attendance_iot = request.env(user=SUPERUSER_ID)["attendance.iot.datas"]
if not attendance_iot.search(
[('employee_id', '=', employee_id.id), ('attendance_number', '=', data.get('sn'))]):
attendance_iot.create({
'attendance_number': data.get('sn'),
'attendance_date': data.get('logs').get('recog_time'),
user_id = data.get('logs')[0].get('user_id')
employee_id = request.env(user=SUPERUSER_ID)["hr.employee"].search([('user_id', '=', user_id.id)])
recog_time_str = data.get('logs')[0].get("recog_time")
checkin_time = datetime.strptime(recog_time_str, "%Y-%m-%d %H:%M:%S")
attendance_iot_id = request.env(user=SUPERUSER_ID)["attendance.iot"].search([('name', '=', data.get('sn'))])
if employee_id:
request.env(user=SUPERUSER_ID)["hr.attendance.details"].create({
'employee_id': employee_id.id,
'checkin_time': checkin_time,
'source': 'iot',
'attendance_iot_id': attendance_iot_id.id,
'location_title': data.get('logs')[0].get("location").get('address'),
})
print("---------------------------------------------测试成功---------------------------------------")
return {"Result": 0, "Msg": "添加成功"}
+1
View File
@@ -1,4 +1,5 @@
from . import hr_employee
from . import attendance_iot_user
from . import attendance_iot
from . import attendance_iot_datas
from . import attendance_iot_manager
+2
View File
@@ -11,3 +11,5 @@ class AttendanceIot(models.Model):
attendance_address = fields.Char(string="设备地址")
broker = fields.Char(string='服务器地址/ip')
port = fields.Char(string='端口号')
id_valid = fields.Datetime(string="设备有效期")
@@ -14,8 +14,6 @@ class AttendanceIotManager(models.Model):
attendance_iot_id = fields.Many2one('attendance.iot', string="设备号")
attendance_address = fields.Char(string="设备地址")
employee_id = fields.Many2one('hr.employee', string="员工")
id_valid = fields.Date(string="数据有效期")
data_selection = fields.Selection([('mqtt', 'mqtt'), ('api', 'api')], default="mqtt", string="数据类型")
def action_attendance_iot_manager(self):
@@ -29,9 +27,10 @@ class AttendanceIotManager(models.Model):
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals['data_selection'] == 'mqtt':
self.mqtt_request(self, vals['attendance_number'], 'addUser')
pass
# for vals in vals_list:
# if vals['data_selection'] == 'mqtt':
# self.mqtt_request(self, vals['attendance_number'], 'addUser')
return super().create(vals_list)
def mqtt_request(self, attendance_number, data):
@@ -88,3 +87,19 @@ class AttendanceIotManager(models.Model):
_logger.info(f"操作失败,返回错误码: {res.get('code')}")
client.disconnect()
def employee_message(self):
domain = [('attendance_iot_id', '=', self.attendance_iot_id.id)]
return {
'name': '员工列表',
'type': 'ir.actions.act_window',
'res_model': 'attendance.iot.user',
'view_mode': 'tree',
'domain': domain,
'target': 'current'
}
@@ -0,0 +1,13 @@
from odoo import api, fields, models, tools
from odoo.exceptions import ValidationError
class AttendanceIotUser(models.Model):
_name = 'attendance.iot.user'
attendance_iot_id = fields.Many2one('attendance.iot', string="设备号")
attendance_address = fields.Char(string="设备地址")
employee_id = fields.Many2one('hr.employee', string="员工")
department_id = fields.Many2one(related='employee_id.department_id', string="部门")
company_id = fields.Many2one(related='employee_id.company_id', string="公司", store=True)
id_valid = fields.Date(string="有效日期")
+1 -1
View File
@@ -6,4 +6,4 @@ class HrEmployee(models.Model):
_inherit = "hr.employee"
_description = "考勤机和用户信息的绑定"
attendance_iot_ids = fields.One2many('attendance.iot.manager', 'employee_id', string="考勤机信息")
attendance_iot_ids = fields.One2many('attendance.iot.user', 'employee_id', string="考勤机信息")
+2 -1
View File
@@ -2,4 +2,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_attendance_iot,attendance_iot,model_attendance_iot,base.group_user,1,1,1,1
access_attendance_iot_manager,attendance_iot_manager,model_attendance_iot_manager,base.group_user,1,1,1,1
access_attendance_iot_manager_wizard,attendance_iot_manager_wizard,model_attendance_iot_manager_wizard,base.group_user,1,1,1,1
access_attendance_iot_datas,attendance_iot_datas,model_attendance_iot_datas,base.group_user,1,1,1,1
access_attendance_iot_datas,attendance_iot_datas,model_attendance_iot_datas,base.group_user,1,1,1,1
access_attendance_iot_user,attendance_iot_user,model_attendance_iot_user,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_attendance_iot attendance_iot model_attendance_iot base.group_user 1 1 1 1
3 access_attendance_iot_manager attendance_iot_manager model_attendance_iot_manager base.group_user 1 1 1 1
4 access_attendance_iot_manager_wizard attendance_iot_manager_wizard model_attendance_iot_manager_wizard base.group_user 1 1 1 1
5 access_attendance_iot_datas attendance_iot_datas model_attendance_iot_datas base.group_user 1 1 1 1
6 access_attendance_iot_user attendance_iot_user model_attendance_iot_user base.group_user 1 1 1 1
@@ -7,9 +7,8 @@
<tree string="考勤机设备管理" editable="bottom">
<field name="attendance_iot_id"/>
<field name="attendance_address"/>
<field name="employee_id" required="1"/>
<field name="id_valid" required="1"/>
<field name="data_selection" required="1"/>
<button name="employee_message" string="员工数据" type="object" class="oe_highlight"/>
</tree>
</field>
</record>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="attendance_iot_user_tree" model="ir.ui.view">
<field name="name">attendance.iot.user.tree</field>
<field name="model">attendance.iot.user</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="attendance_iot_id"/>
<field name="employee_id"/>
<field name="department_id"/>
<field name="company_id"/>
</tree>
</field>
</record>
</odoo>
@@ -9,6 +9,7 @@
<field name="attendance_address"/>
<field name="broker"/>
<field name="port"/>
<field name="id_valid"/>
</tree>
</field>
</record>
@@ -8,10 +8,10 @@
<xpath expr="//page[@name='hr_settings']" position="after">
<page string="考勤机信息">
<field name="attendance_iot_ids">
<tree>
<tree editable="bottom">
<field name="attendance_iot_id"/>
<field name="attendance_address"/>
<field name="employee_id"/>
<field name="employee_id" column_invisible="1"/>
<field name="id_valid"/>
</tree>
</field>
@@ -11,8 +11,8 @@
<group invisible="node_btn_name in ['分发', '结束', '收回']">
<div class="oe_comment_block" style=" width:1200%; border: 1px solid #dee2e6; border-radius: 4px; padding: 12px; margin-bottom: 16px;">
<label for="comment_note_id" string="常用意见" domain="[('note_setting_id.users_role_ids', 'in', user_role_id)]"
style="font-weight: bold; margin-bottom: 8px; display: block;" options="{'no_create': True}"/>
<field name="comment_note_id" class="mb-3" style="width: 100%;"/>
style="font-weight: bold; margin-bottom: 8px; display: block;"/>
<field name="comment_note_id" class="mb-3" style="width: 100%;" options="{'no_create': True}"/>
<field name="comment_note" placeholder="请输入意见内容..." style="width: 100%;"/>
</div>
</group>
@@ -21,7 +21,7 @@
<div class="oe_comment_block" style=" width:1200%; border: 1px solid #dee2e6; border-radius: 4px; padding: 12px; margin-bottom: 16px;">
<label for="comment_note_id" string="结束意见" domain="[('note_setting_id.users_role_ids', 'in', user_role_id)]"
style="font-weight: bold; margin-bottom: 8px; display: block;"/>
<field name="comment_note_id" class="mb-3" style="width: 100%;"/>
<field name="comment_note_id" class="mb-3" style="width: 100%;" options="{'no_create': True}"/>
<field name="comment_note" placeholder="请输入意见内容..." style="width: 100%;"/>
</div>
</group>
@@ -29,7 +29,7 @@
<div class="oe_comment_block" style=" width:1200%; border: 1px solid #dee2e6; border-radius: 4px; padding: 12px; margin-bottom: 16px;">
<label for="comment_note_id" string="分发意见" domain="[('note_setting_id.users_role_ids', 'in', user_role_id)]"
style="font-weight: bold; margin-bottom: 8px; display: block;"/>
<field name="comment_note_id" class="mb-3" style="width: 100%;"/>
<field name="comment_note_id" class="mb-3" style="width: 100%;" options="{'no_create': True}"/>
<field name="comment_note" placeholder="请输入意见内容..." style="width: 100%;"/>
</div>
</group>
+10
View File
@@ -0,0 +1,10 @@
#. module: base
#. odoo-python
#: code:addons/base/models/ir_rule.py:0
#, python-format
msgid ""
"Uh-oh! Looks like you have stumbled upon some top-secret records.\n"
"\n"
"Sorry, %s doesn't have '%s' access to:"
msgstr ""
"对不起,%s没有'%s'来访问:"
@@ -21,9 +21,14 @@ class AppletAttendance(Controller):
'user_id': 用户id
'check_in': [上班卡,正常]
'check_out': [下班卡,早退]
'state': 是否可以打卡
'state_result': 不可打卡原因
'state': 是否可以打卡['yes', 'no']
'state_result': 不可打卡原因 'xxx'
}
# 0.判断是否有用户,否则返回“此用户无权限”
# 1.根据经纬度判断是否可以打卡,如果不可以就直接返回“超出范围,不允许打卡”
# 2.把这个人的地址location,class,user_id,state-yes,state_result=''
# 2.check_in "YYYY-MM-DD HH:MM:SS" ['', ''] 如果没有传 ''
# 2.check_out "YYYY-MM-DD HH:MM:SS" ['', ''] 如果没有传 ''
"""
user_id = int(kw.get('id'))
user_id = request.env(user=SUPERUSER_ID)["res.user"].search([('wecom_id', '=', data.get('user_id'))])
@@ -60,7 +65,7 @@ class AppletAttendance(Controller):
小程序创建打卡记录
:return:
"""
data = request.httprequest.json
user_id = int(kw.get('id'))
user_name = data.get('user_id')
employee_id = request.env(user=SUPERUSER_ID)["hr.employee"].search([('user_id', '=', user_name.id)])
if not employee_id:
@@ -40,6 +40,8 @@ class HrAttendanceDetail(models.Model):
employee_id = fields.Many2one('hr.employee', string="员工", readonly=True)
company_id = fields.Many2one('res.company', string="公司", related="employee_id.company_id", store=True)
department_id = fields.Many2one('hr.department', string="部门", related="employee_id.department_id", readonly=True, store=True)
source = fields.Selection([('iot', '考勤机'), ('mini_programs', '小程序')], string="来源")
attendance_iot_id = fields.Many2one('attendance.iot', string="设备号")
userid = fields.Char(string='userid')
groupname = fields.Char(string='打卡规则名称')
checkin_type = fields.Char(string='打卡类型')
@@ -37,8 +37,8 @@
<field name="employee_id" widget="ztree_select"/>
<field name="company_id" optional="hide"/>
<field name="department_id" widget="ztree_select"/>
<field name="groupname"/>
<field name="checkin_type"/>
<field name="source"/>
<field name="attendance_iot_id"/>
<field name="checkin_time"/>
<field name="sch_checkin_time"/>
</tree>
@@ -34,4 +34,14 @@ class InheritHrPayslipRun(models.Model):
rec.run_stage = 'issued'
def open_payslip(self):
return {
"name": "详情",
'type': 'ir.actions.act_window',
'res_model': 'hr.payslip.run',
"view_mode": "form",
"res_id": self.id,
}
@@ -16,6 +16,7 @@
<field name="run_stage" readonly="1"/>
<button type="object" name="Fileline" string="归档明细" class="oe_highlight"/>
<button type="object" name="add_comment" string="完成" class="oe_highlight" invisible="run_stage == 'issued'"/>
<button type="object" name="open_payslip" string="详情" class="oe_highlight"/>
</xpath>
</field>
</record>
@@ -12,7 +12,7 @@ class YuthonMessageApproval(models.Model):
code = fields.Char(string="编号",
default=lambda self: self.env['ir.sequence'].next_by_code('yuthon_leaving_approval_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="发布部门")
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="发布部门", domain=[])
phone = fields.Char(related='users_id.employee_id.mobile_phone', string="联系方式")
documents_ids = fields.Many2many('ir.attachment', string="附件")
publish_ids = fields.Many2many('yuthon.publish.type', string="发布平台")
+2 -2
View File
@@ -184,7 +184,7 @@
parent="hr_attendance_root_board_menu"
sequence="20"/>
<menuitem id="menu_attendance_iot_manager"
name="考勤机设备"
name="员工管理"
parent="time_attendance_machine_management"
action="attendance_iot.attendance_iot_manager_action"
sequence="1"/>
@@ -194,7 +194,7 @@
action="attendance_iot.attendance_iot_datas_action"
sequence="10"/>
<menuitem id="menu_attendance_iot"
name="考勤机设备"
name="设备管理"
parent="time_attendance_machine_management"
action="attendance_iot.attendance_iot_action"
sequence="21"/>