diff --git a/apps/hrm/migrations/0010_alter_clockrecord_type.py b/apps/hrm/migrations/0010_alter_clockrecord_type.py new file mode 100644 index 00000000..267ef099 --- /dev/null +++ b/apps/hrm/migrations/0010_alter_clockrecord_type.py @@ -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='打卡类型'), + ), + ] diff --git a/apps/hrm/models.py b/apps/hrm/models.py index 11ef8ba5..4ce8aa0b 100755 --- a/apps/hrm/models.py +++ b/apps/hrm/models.py @@ -79,9 +79,11 @@ class ClockRecord(BaseModel): """ ClOCK_ON = 10 CLOCK_OFF = 20 + CLOCK_ING = 30 type_choice = ( (ClOCK_ON, '上班打卡'), (CLOCK_OFF, '下班打卡'), + (CLOCK_ING, '忽略'), # 尽量不用 ) E_TYPE_LESS = 10 E_TYPE_MORE = 20 diff --git a/apps/hrm/services.py b/apps/hrm/services.py index 53b9d4ee..49405a3e 100755 --- a/apps/hrm/services.py +++ b/apps/hrm/services.py @@ -211,10 +211,11 @@ class HrmService: """ id_number = data['info']['extend'].get('paperNumber', None) if id_number: - nodeCode = data['info']['nodeCode'] + detail = {'id':data['info']['extend']['id']} + nodeCode = data['info']['extend']['acsChannelCode'] swip_time = data['info']['extend']['swingTime'] 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 def swipe_offline(cls, data:dict): @@ -223,177 +224,88 @@ class HrmService: for i in data['infoArray']: id_number = i.get('paperNumber', None) if id_number: + detail = {'id':i['id']} nodeCode = i['acsChannelCode'] swip_time = i['swingTime'] 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 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.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() - 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') 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, 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, 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() - # 进行相关方/访客项目更新 - 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) + card_type = 30 + trigger = 'door' + if e_type == 1: + card_type = 10 + elif e_type == 2: + card_type = 20 + else: + trigger = 'panel' - # 此处可触发安全帽事件逻辑 \ No newline at end of file + # 先直接创建记录 + 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() + + + + + # 此处可触发安全帽事件逻辑 \ No newline at end of file diff --git a/apps/hrm/tasks.py b/apps/hrm/tasks.py index 005f291d..73d497f8 100755 --- a/apps/hrm/tasks.py +++ b/apps/hrm/tasks.py @@ -1,14 +1,13 @@ from __future__ import absolute_import, unicode_literals from celery import shared_task -from apps.hrm.models import Employee +from apps.hrm.models import Employee, ClockRecord from dateutil import tz from datetime import datetime, timedelta from apps.third.dahua import dhClient from apps.third.tapis import dhapis from apps.hrm.services import HrmService from django.utils import timezone -from datetime import timedelta import time @@ -27,14 +26,22 @@ def correct_swip_task(start_time="", end_time=""): # for i in lgs: # HrmService.swipe(data=eval(i.data)) # 从大华历史记录校正打卡记录 - now = timezone.now() + now = datetime.now() if start_time == "": - start_time = (now - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S") - elif end_time == "": + start_time = (now - timedelta(hours=25)).strftime("%Y-%m-%d %H:%M:%S") + if end_time == "": 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 = { "pageNum":1, - "pageSize":"400", + "pageSize": str(count), "startSwingTime":start_time, "endSwingTime":end_time, "openType":"61" @@ -42,6 +49,7 @@ def correct_swip_task(start_time="", end_time=""): _, res = dhClient.request(**dhapis['swipe_list'], json=data) for i in res['pageData']: HrmService.swipe_next(i['channelCode'], i['paperNumber'], i['swingTime'], i['enterOrExit'], i) + # ClockRecord.objects.filter(type=30).delete() @shared_task def correct_card_time(): diff --git a/apps/third/tapis.py b/apps/third/tapis.py index 45a51500..6378e351 100755 --- a/apps/third/tapis.py +++ b/apps/third/tapis.py @@ -109,7 +109,11 @@ dhapis = { "method": "get" }, "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" }, "dev_snap": {