feat: 打卡记录增加忽略记录项目并进行代码优化
This commit is contained in:
parent
7cec134265
commit
16daa861bd
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.12 on 2023-03-15 07:40
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hrm', '0009_alter_clockrecord_exception_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='clockrecord',
|
||||||
|
name='type',
|
||||||
|
field=models.PositiveSmallIntegerField(choices=[(10, '上班打卡'), (20, '下班打卡'), (30, '忽略')], default=10, verbose_name='打卡类型'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -79,9 +79,11 @@ class ClockRecord(BaseModel):
|
||||||
"""
|
"""
|
||||||
ClOCK_ON = 10
|
ClOCK_ON = 10
|
||||||
CLOCK_OFF = 20
|
CLOCK_OFF = 20
|
||||||
|
CLOCK_ING = 30
|
||||||
type_choice = (
|
type_choice = (
|
||||||
(ClOCK_ON, '上班打卡'),
|
(ClOCK_ON, '上班打卡'),
|
||||||
(CLOCK_OFF, '下班打卡'),
|
(CLOCK_OFF, '下班打卡'),
|
||||||
|
(CLOCK_ING, '忽略'), # 尽量不用
|
||||||
)
|
)
|
||||||
E_TYPE_LESS = 10
|
E_TYPE_LESS = 10
|
||||||
E_TYPE_MORE = 20
|
E_TYPE_MORE = 20
|
||||||
|
|
|
@ -211,10 +211,11 @@ class HrmService:
|
||||||
"""
|
"""
|
||||||
id_number = data['info']['extend'].get('paperNumber', None)
|
id_number = data['info']['extend'].get('paperNumber', None)
|
||||||
if id_number:
|
if id_number:
|
||||||
nodeCode = data['info']['nodeCode']
|
detail = {'id':data['info']['extend']['id']}
|
||||||
|
nodeCode = data['info']['extend']['acsChannelCode']
|
||||||
swip_time = data['info']['extend']['swingTime']
|
swip_time = data['info']['extend']['swingTime']
|
||||||
e_type = data['info']['extend']['enterOrExit']
|
e_type = data['info']['extend']['enterOrExit']
|
||||||
cls.swipe_next(nodeCode, id_number, swip_time, e_type, data['info']['extend'])
|
cls.swipe_next(nodeCode, id_number, swip_time, e_type, detail)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def swipe_offline(cls, data:dict):
|
def swipe_offline(cls, data:dict):
|
||||||
|
@ -223,177 +224,88 @@ class HrmService:
|
||||||
for i in data['infoArray']:
|
for i in data['infoArray']:
|
||||||
id_number = i.get('paperNumber', None)
|
id_number = i.get('paperNumber', None)
|
||||||
if id_number:
|
if id_number:
|
||||||
|
detail = {'id':i['id']}
|
||||||
nodeCode = i['acsChannelCode']
|
nodeCode = i['acsChannelCode']
|
||||||
swip_time = i['swingTime']
|
swip_time = i['swingTime']
|
||||||
e_type = i['enterOrExit']
|
e_type = i['enterOrExit']
|
||||||
Thread(target=cls.swipe_next, args=(nodeCode, id_number, swip_time, e_type, i), daemon=True).start()
|
cls.swipe_next(nodeCode, id_number, swip_time, e_type, detail)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def swipe_next(cls, nodeCode: str, id_number: str, swip_time: str, e_type:int, detail:dict):
|
def swipe_next(cls, nodeCode: str, id_number: str, swip_time: str, e_type:int, detail:dict):
|
||||||
from apps.vm.models import Visit
|
from apps.vm.models import Visit
|
||||||
from apps.rpm.models import Rpj
|
from apps.rpm.models import Rpj
|
||||||
|
|
||||||
|
# 进行相关方/访客项目更新
|
||||||
|
Visit.objects.filter(state=Visit.V_ENTER, visitors__employee__id_number=id_number).update(
|
||||||
|
state=Visit.V_WORKING)
|
||||||
|
Rpj.objects.filter(state=Rpj.RPJ_ENTER, remployees__employee__id_number=id_number).update(
|
||||||
|
state=Rpj.RPJ_WORKING)
|
||||||
|
|
||||||
|
# 打卡处理
|
||||||
device = TDevice.objects.filter(code=nodeCode).first()
|
device = TDevice.objects.filter(code=nodeCode).first()
|
||||||
if device:
|
ep = Employee.objects.filter(id_number=id_number, type__in=["employee", "remployee"]).first()
|
||||||
|
if device and device.is_clock and ep:
|
||||||
tzinfo = tz.gettz('Asia/Shanghai')
|
tzinfo = tz.gettz('Asia/Shanghai')
|
||||||
s_time_f = datetime.strptime(swip_time, "%Y-%m-%d %H:%M:%S").replace(tzinfo=tzinfo)
|
s_time_f = datetime.strptime(swip_time, "%Y-%m-%d %H:%M:%S").replace(tzinfo=tzinfo)
|
||||||
first_time = datetime(year=s_time_f.year, month=s_time_f.month, day=s_time_f.day,
|
first_time = datetime(year=s_time_f.year, month=s_time_f.month, day=s_time_f.day,
|
||||||
hour=0, minute=0, second=0, tzinfo=tzinfo)
|
hour=0, minute=0, second=0, tzinfo=tzinfo)
|
||||||
end_time = datetime(year=s_time_f.year, month=s_time_f.month, day=s_time_f.day,
|
end_time = datetime(year=s_time_f.year, month=s_time_f.month, day=s_time_f.day,
|
||||||
hour=23, minute=59, second=59, tzinfo=tzinfo)
|
hour=23, minute=59, second=59, tzinfo=tzinfo)
|
||||||
if device.is_clock:
|
|
||||||
# 如果设置为关联考勤
|
|
||||||
# myLogger.info(data['info']['extend'])
|
|
||||||
if e_type == 1:
|
|
||||||
# 如果是进门
|
|
||||||
ep = Employee.objects.filter(id_number=id_number, type__in=["employee", "remployee"]).first()
|
|
||||||
# 如果是内部/相关方员工创建上班打卡记录(更新)
|
|
||||||
if ep:
|
|
||||||
cr_10 = ClockRecord.objects.filter(
|
|
||||||
type=10, employee=ep, create_time__gte=first_time, create_time__lte=end_time).first()
|
|
||||||
if cr_10:
|
|
||||||
if s_time_f < cr_10.create_time:
|
|
||||||
cr_10.create_time = s_time_f
|
|
||||||
cr_10.trigger = 'door'
|
|
||||||
cr_10.detail = detail
|
|
||||||
cr_10.save()
|
|
||||||
else:
|
|
||||||
cr_10 = ClockRecord()
|
|
||||||
cr_10.type = 10
|
|
||||||
cr_10.employee = ep
|
|
||||||
cr_10.trigger = 'door'
|
|
||||||
cr_10.detail = detail
|
|
||||||
cr_10.create_time = s_time_f
|
|
||||||
cr_10.save()
|
|
||||||
ep.is_atwork = True
|
|
||||||
ep.last_check_time = s_time_f
|
|
||||||
ep.save()
|
|
||||||
elif e_type == 2:
|
|
||||||
# 如果是出门
|
|
||||||
ep = Employee.objects.filter(id_number=id_number, type__in=[
|
|
||||||
"employee", "remployee"]).first()
|
|
||||||
# 如果是内部/相关方员工创建下班打卡记录(更新)
|
|
||||||
if ep:
|
|
||||||
cr_20 = ClockRecord.objects.filter(
|
|
||||||
type=20, employee=ep, create_time__gte=first_time, create_time__lte=end_time).first()
|
|
||||||
if cr_20:
|
|
||||||
cr_20.exception_type = None
|
|
||||||
if s_time_f > cr_20.create_time:
|
|
||||||
cr_20.create_time = s_time_f
|
|
||||||
cr_20.trigger = 'door'
|
|
||||||
cr_20.detail = detail
|
|
||||||
cr_20.save()
|
|
||||||
else:
|
|
||||||
cr_20 = ClockRecord()
|
|
||||||
cr_20.type = 20
|
|
||||||
cr_20.employee = ep
|
|
||||||
cr_20.trigger = 'door'
|
|
||||||
cr_20.detail = detail
|
|
||||||
cr_20.create_time = s_time_f
|
|
||||||
cr_20.save()
|
|
||||||
ep.is_atwork = False
|
|
||||||
ep.last_check_time = s_time_f
|
|
||||||
ep.save()
|
|
||||||
# 判断是否有异常
|
|
||||||
# 找到最近的打卡时间
|
|
||||||
cr_e = ClockRecord.objects.filter(create_time__lt=cr_20.create_time, employee=ep).exclude(id=cr_20.id).order_by('-create_time').first()
|
|
||||||
if cr_e:
|
|
||||||
time_d = cr_20.create_time - cr_e.create_time
|
|
||||||
if cr_e.type == 10:
|
|
||||||
if time_d < timedelta(hours=7):
|
|
||||||
cr_20.exception_type = ClockRecord.E_TYPE_LESS
|
|
||||||
cr_20.save()
|
|
||||||
elif time_d > timedelta(hours=14):
|
|
||||||
cr_20.exception_type = ClockRecord.E_TYPE_MORE
|
|
||||||
cr_20.save()
|
|
||||||
elif time_d > timedelta(hours=9):
|
|
||||||
cr_20.exception_type = ClockRecord.E_TYPE_ADD
|
|
||||||
cr_20.save()
|
|
||||||
elif cr_e.type == 20:
|
|
||||||
cr_20.exception_type = ClockRecord.E_TYPE_MISS
|
|
||||||
cr_20.save()
|
|
||||||
elif e_type == 3:
|
|
||||||
# 如果不确定根据时间来
|
|
||||||
card_type = None
|
|
||||||
time_10_x = datetime(year=s_time_f.year, month=s_time_f.month,
|
|
||||||
day=s_time_f.day, hour=3, minute=0, second=0, tzinfo=tzinfo)
|
|
||||||
time_10_y = datetime(year=s_time_f.year, month=s_time_f.month,
|
|
||||||
day=s_time_f.day, hour=11, minute=0, second=0, tzinfo=tzinfo)
|
|
||||||
time_20_x = datetime(year=s_time_f.year, month=s_time_f.month,
|
|
||||||
day=s_time_f.day, hour=16, minute=0, second=0, tzinfo=tzinfo)
|
|
||||||
time_20_y = datetime(year=s_time_f.year, month=s_time_f.month,
|
|
||||||
day=s_time_f.day, hour=23, minute=0, second=0, tzinfo=tzinfo)
|
|
||||||
if time_10_x < s_time_f < time_10_y:
|
|
||||||
card_type = 10
|
|
||||||
elif time_20_x < s_time_f < time_20_y:
|
|
||||||
card_type = 20
|
|
||||||
if card_type:
|
|
||||||
ep = Employee.objects.filter(id_number=id_number, type__in=[
|
|
||||||
"employee", "remployee"]).first()
|
|
||||||
# 如果是内部/相关方员工创建下班打卡记录(更新)
|
|
||||||
if ep and card_type == 10:
|
|
||||||
cr_10 = ClockRecord.objects.filter(
|
|
||||||
type=10, employee=ep, create_time__gte=first_time, create_time__lte=end_time).first()
|
|
||||||
if cr_10:
|
|
||||||
if s_time_f < cr_10.create_time:
|
|
||||||
cr_10.create_time = s_time_f
|
|
||||||
cr_10.trigger = 'panel'
|
|
||||||
cr_10.detail = detail
|
|
||||||
cr_10.save()
|
|
||||||
else:
|
|
||||||
cr_10 = ClockRecord()
|
|
||||||
cr_10.type = 10
|
|
||||||
cr_10.employee = ep
|
|
||||||
cr_10.trigger = 'panel'
|
|
||||||
cr_10.detail = detail
|
|
||||||
cr_10.create_time = s_time_f
|
|
||||||
cr_10.save()
|
|
||||||
ep.is_atwork = True
|
|
||||||
ep.last_check_time = s_time_f
|
|
||||||
ep.save()
|
|
||||||
elif ep and card_type == 20:
|
|
||||||
cr_20 = ClockRecord.objects.filter(
|
|
||||||
type=20, employee=ep, create_time__gte=first_time, create_time__lte=end_time).first()
|
|
||||||
if cr_20:
|
|
||||||
cr_20.exception_type = None
|
|
||||||
if s_time_f > cr_20.create_time:
|
|
||||||
cr_20.create_time = s_time_f
|
|
||||||
cr_20.trigger = 'panel'
|
|
||||||
cr_20.detail = detail
|
|
||||||
cr_20.save()
|
|
||||||
else:
|
|
||||||
cr_20 = ClockRecord()
|
|
||||||
cr_20.type = 20
|
|
||||||
cr_20.employee = ep
|
|
||||||
cr_20.trigger = 'panel'
|
|
||||||
cr_20.detail = detail
|
|
||||||
cr_20.create_time = s_time_f
|
|
||||||
cr_20.save()
|
|
||||||
ep.is_atwork = False
|
|
||||||
ep.last_check_time = s_time_f
|
|
||||||
ep.save()
|
|
||||||
# 判断是否有异常
|
|
||||||
# 找到最近的打卡时间
|
|
||||||
cr_e = ClockRecord.objects.filter(create_time__lt=cr_20.create_time, employee=ep).exclude(id=cr_20.id).order_by('-create_time').first()
|
|
||||||
if cr_e:
|
|
||||||
time_d = cr_20.create_time - cr_e.create_time
|
|
||||||
if cr_e.type == 10:
|
|
||||||
if time_d < timedelta(hours=7):
|
|
||||||
cr_20.exception_type = ClockRecord.E_TYPE_LESS
|
|
||||||
cr_20.save()
|
|
||||||
elif time_d > timedelta(hours=14):
|
|
||||||
cr_20.exception_type = ClockRecord.E_TYPE_MORE
|
|
||||||
cr_20.save()
|
|
||||||
elif time_d > timedelta(hours=9):
|
|
||||||
cr_20.exception_type = ClockRecord.E_TYPE_ADD
|
|
||||||
cr_20.save()
|
|
||||||
elif cr_e.type == 20:
|
|
||||||
cr_20.exception_type = ClockRecord.E_TYPE_MISS
|
|
||||||
cr_20.save()
|
|
||||||
|
|
||||||
# 进行相关方/访客项目更新
|
card_type = 30
|
||||||
Visit.objects.filter(state=Visit.V_ENTER, visitors__employee__id_number=id_number).update(
|
trigger = 'door'
|
||||||
state=Visit.V_WORKING)
|
if e_type == 1:
|
||||||
Rpj.objects.filter(state=Rpj.RPJ_ENTER, remployees__employee__id_number=id_number).update(
|
card_type = 10
|
||||||
state=Rpj.RPJ_WORKING)
|
elif e_type == 2:
|
||||||
|
card_type = 20
|
||||||
|
else:
|
||||||
|
trigger = 'panel'
|
||||||
|
|
||||||
# 此处可触发安全帽事件逻辑
|
# 先直接创建记录
|
||||||
|
ClockRecord.objects.get_or_create(employee=ep, create_time=s_time_f, defaults={'type':card_type, 'employee':ep, 'trigger': trigger, 'detail': detail, 'create_time': s_time_f})
|
||||||
|
|
||||||
|
if card_type == 10:
|
||||||
|
# 查找当天的进门记录
|
||||||
|
cr_10_q = ClockRecord.objects.filter(
|
||||||
|
type=10, employee=ep, create_time__gte=first_time, create_time__lte=end_time)
|
||||||
|
first_obj = cr_10_q.order_by('create_time').first()
|
||||||
|
cr_10_q.exclude(id=first_obj.id).update(type=30)
|
||||||
|
elif card_type == 20:
|
||||||
|
# 查找当天的出门记录
|
||||||
|
cr_20_q = ClockRecord.objects.filter(
|
||||||
|
type=20, employee=ep, create_time__gte=first_time, create_time__lte=end_time)
|
||||||
|
last_obj = cr_20_q.order_by('-create_time').first()
|
||||||
|
cr_20_q.exclude(id=last_obj.id).update(type=30)
|
||||||
|
# 判断是否有异常
|
||||||
|
# 找到最近的上下打卡时间不一定是当天的
|
||||||
|
cr_e = ClockRecord.objects.filter(create_time__lt=last_obj.create_time, employee=ep, type__in=[10, 20]).order_by('-create_time').first()
|
||||||
|
if cr_e:
|
||||||
|
time_d = last_obj.create_time - cr_e.create_time
|
||||||
|
if cr_e.type == 10:
|
||||||
|
if time_d < timedelta(hours=7):
|
||||||
|
last_obj.exception_type = ClockRecord.E_TYPE_LESS
|
||||||
|
last_obj.save()
|
||||||
|
elif time_d > timedelta(hours=14):
|
||||||
|
last_obj.exception_type = ClockRecord.E_TYPE_MORE
|
||||||
|
last_obj.save()
|
||||||
|
elif time_d > timedelta(hours=9):
|
||||||
|
last_obj.exception_type = ClockRecord.E_TYPE_ADD
|
||||||
|
last_obj.save()
|
||||||
|
elif cr_e.type == 20:
|
||||||
|
last_obj.exception_type = ClockRecord.E_TYPE_MISS
|
||||||
|
last_obj.save()
|
||||||
|
|
||||||
|
# 记录在岗情况
|
||||||
|
last_obj_t = ClockRecord.objects.filter(employee=ep, type__in=[10,20]).order_by('-create_time').first()
|
||||||
|
if last_obj_t:
|
||||||
|
ep.last_check_time = last_obj_t.create_time
|
||||||
|
if last_obj_t.type == 10:
|
||||||
|
ep.is_atwork = True
|
||||||
|
else:
|
||||||
|
ep.is_atwork = False
|
||||||
|
ep.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 此处可触发安全帽事件逻辑
|
|
@ -1,14 +1,13 @@
|
||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from apps.hrm.models import Employee
|
from apps.hrm.models import Employee, ClockRecord
|
||||||
from dateutil import tz
|
from dateutil import tz
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from apps.third.dahua import dhClient
|
from apps.third.dahua import dhClient
|
||||||
from apps.third.tapis import dhapis
|
from apps.third.tapis import dhapis
|
||||||
from apps.hrm.services import HrmService
|
from apps.hrm.services import HrmService
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import timedelta
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,14 +26,22 @@ def correct_swip_task(start_time="", end_time=""):
|
||||||
# for i in lgs:
|
# for i in lgs:
|
||||||
# HrmService.swipe(data=eval(i.data))
|
# HrmService.swipe(data=eval(i.data))
|
||||||
# 从大华历史记录校正打卡记录
|
# 从大华历史记录校正打卡记录
|
||||||
now = timezone.now()
|
now = datetime.now()
|
||||||
if start_time == "":
|
if start_time == "":
|
||||||
start_time = (now - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
|
start_time = (now - timedelta(hours=25)).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
elif end_time == "":
|
if end_time == "":
|
||||||
end_time = now.strftime("%Y-%m-%d %H:%M:%S")
|
end_time = now.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
data0 = {
|
||||||
|
"pageNum":1,
|
||||||
|
"pageSize": "20",
|
||||||
|
"startSwingTime":start_time,
|
||||||
|
"endSwingTime":end_time,
|
||||||
|
"openType":"61"
|
||||||
|
}
|
||||||
|
_, count = dhClient.request(**dhapis['swipe_list_count'], json=data0)
|
||||||
data = {
|
data = {
|
||||||
"pageNum":1,
|
"pageNum":1,
|
||||||
"pageSize":"400",
|
"pageSize": str(count),
|
||||||
"startSwingTime":start_time,
|
"startSwingTime":start_time,
|
||||||
"endSwingTime":end_time,
|
"endSwingTime":end_time,
|
||||||
"openType":"61"
|
"openType":"61"
|
||||||
|
@ -42,6 +49,7 @@ def correct_swip_task(start_time="", end_time=""):
|
||||||
_, res = dhClient.request(**dhapis['swipe_list'], json=data)
|
_, res = dhClient.request(**dhapis['swipe_list'], json=data)
|
||||||
for i in res['pageData']:
|
for i in res['pageData']:
|
||||||
HrmService.swipe_next(i['channelCode'], i['paperNumber'], i['swingTime'], i['enterOrExit'], i)
|
HrmService.swipe_next(i['channelCode'], i['paperNumber'], i['swingTime'], i['enterOrExit'], i)
|
||||||
|
# ClockRecord.objects.filter(type=30).delete()
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def correct_card_time():
|
def correct_card_time():
|
||||||
|
|
|
@ -109,7 +109,11 @@ dhapis = {
|
||||||
"method": "get"
|
"method": "get"
|
||||||
},
|
},
|
||||||
"swipe_list": {
|
"swipe_list": {
|
||||||
"url": "/evo-apigw/evo-accesscontrol/1.2.0/card/accessControl/swingCardRecord/bycondition/combined",
|
"url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/swingCardRecord/bycondition/combined",
|
||||||
|
"method": "post"
|
||||||
|
},
|
||||||
|
"swipe_list_count": {
|
||||||
|
"url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/swingCardRecord/bycondition/combinedCount",
|
||||||
"method": "post"
|
"method": "post"
|
||||||
},
|
},
|
||||||
"dev_snap": {
|
"dev_snap": {
|
||||||
|
|
Loading…
Reference in New Issue