factory/apps/hrm/models.py

192 lines
7.3 KiB
Python
Executable File

from django.db import models
from apps.system.models import Post, User
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBModel
from django.utils import timezone
from datetime import timedelta
class Employee(CommonBModel):
"""
TN:员工信息
"""
JOB_ON = 10
JOB_OFF = 20
JOB_RETIRE = 30
jobstate_choices = (
(JOB_ON, '在职'),
(JOB_OFF, '离职'),
(JOB_RETIRE, '退休')
)
PEOPLE_TYPE_CHOICES = (
('employee', '内部员工'),
('remployee', '相关方人员'),
('visitor', '访客'),
('driver', '司机')
)
type = models.CharField('人员类型', default='employee',
max_length=10, choices=PEOPLE_TYPE_CHOICES)
user = models.OneToOneField(User,
verbose_name='系统账号',
related_name='employee',
on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField('姓名', max_length=20)
phone = models.CharField('手机号', max_length=11, null=True, blank=True)
email = models.EmailField('邮箱号', null=True, blank=True)
number = models.CharField('人员编号', max_length=50, null=True, blank=True)
photo = models.CharField('证件照', max_length=1000, null=True, blank=True)
id_number = models.CharField(
'身份证号', max_length=100, null=True, blank=True, unique=True)
gender = models.CharField('性别', max_length=10, default='')
signature = models.CharField('签名图片', max_length=200, null=True, blank=True)
birthday = models.DateField('出生年月日', null=True, blank=True)
qualification = models.CharField(
'学历', max_length=50, null=True, blank=True)
job_state = models.IntegerField(
'在职状态', choices=jobstate_choices, default=10)
is_atwork = models.BooleanField('当前在岗', default=False)
show_atwork = models.BooleanField('是否展示在岗状态', default=True)
last_check_time = models.DateTimeField('打卡时间', null=True, blank=True)
not_work_remark = models.CharField(
'当前未打卡说明', null=True, blank=True, max_length=200)
third_info = models.JSONField(
'三方信息', default=dict, null=False, blank=True) # 主要是定位卡信息
post = models.ForeignKey(Post, verbose_name='所属岗位',
on_delete=models.SET_NULL, null=True, blank=True)
face_data = models.JSONField(
'人脸数据', null=True, blank=True) # 存储的是字典(模型名:人脸数据)
class Meta:
verbose_name = '员工补充信息'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
def save(self, *args, **kwargs) -> None:
return super().save(*args, **kwargs)
# class Card(CommonAModel):
# """
# 卡
# """
# CARD_FACE = 10
# CARD_LOCATION = 20
class NotWorkRemark(CommonADModel):
"""
TN:离岗说明
"""
not_work_date = models.DateField('未打卡日期')
user = models.ForeignKey(User, verbose_name='用户', on_delete=models.CASCADE)
remark = models.CharField('未打卡说明', null=True, blank=True, max_length=200)
class Attendance(CommonADModel):
"""
TN:到岗记录
"""
ATT_STATE_CHOICES = [
('pending', '待定'),
('normal', '正常'),
('late', '迟到'),
('early_leave', '早退'),
('absent', '未到岗'),
('leave', '请假'),
# 可以根据需要添加更多状态
]
user = models.ForeignKey(
User, verbose_name='关联人员', on_delete=models.CASCADE)
work_date = models.DateField('工作日期')
shift = models.ForeignKey(
'mtm.shift', verbose_name='班次', on_delete=models.CASCADE)
team = models.ForeignKey('mtm.team', verbose_name='班组',
on_delete=models.SET_NULL, null=True, blank=True)
post = models.ForeignKey('system.post', verbose_name='岗位',
on_delete=models.SET_NULL, null=True, blank=True)
work_time_start = models.DateTimeField('工作开始时间')
work_time_end = models.DateTimeField('工作结束时间')
state = models.CharField('状态', max_length=20,
choices=ATT_STATE_CHOICES, default='pending', help_text=str(ATT_STATE_CHOICES))
note = models.TextField('备注信息', default='', blank=True)
# class Meta:
# unique_together = ('user', 'work_date', 'shift')
class ClockRecord(BaseModel):
"""
TN:打卡记录
"""
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
E_TYPE_MISS = 30
E_TYPE_ADD = 40
E_TYPE_CHOISE = (
(E_TYPE_LESS, '在岗时间短'),
(E_TYPE_MORE, '在岗时间长'),
(E_TYPE_MISS, '缺卡'),
(E_TYPE_ADD, '加班')
)
type = models.PositiveSmallIntegerField(
'打卡类型', choices=type_choice, default=ClOCK_ON)
employee = models.ForeignKey(
Employee, verbose_name='对应人员', on_delete=models.CASCADE)
clock_time = models.DateTimeField('打卡时间', null=True, blank=True)
# panel, location, door, manual
trigger = models.CharField('触发', max_length=20)
detail = models.JSONField('相关记录', default=dict,
null=False, blank=True) # 里面主要有对应的ID值
exception_type = models.PositiveSmallIntegerField(
'异常类型', choices=E_TYPE_CHOISE, null=True, blank=True)
note = models.CharField('备注', max_length=20, default='')
attendance = models.ForeignKey(
Attendance, on_delete=models.SET_NULL, verbose_name='关联到岗记录', null=True, blank=True)
class Certificate(CommonAModel):
"""
TN:证书
"""
CERT_OK = 10
CERT_EXPIRING = 20
CERT_EXPIRED = 30
CERTIFICATE_TYPE_CHOICES = (
(10, '特种作业证书'),
(20, '特种设备操作证书'),
(30, '安全管理人员证书')
)
employee = models.ForeignKey(
Employee, verbose_name='对应人员', on_delete=models.CASCADE)
name = models.CharField('证书名称', max_length=20)
number = models.CharField('证书编号', max_length=20)
type = models.PositiveSmallIntegerField('证书类型', default=10)
issue_date = models.DateField('发证日期')
expiration_date = models.DateField('有效期')
state = models.PositiveSmallIntegerField('证书状态', default=CERT_OK, choices=((CERT_OK, '有效'), (CERT_EXPIRING, '即将过期'), (CERT_EXPIRED, '已过期')))
review_date = models.DateField('下一次复审日期')
file = models.TextField('文件地址', null=True, blank=True)
def get_state(self, need_update=False):
now = timezone.now().date()
new_state = self.CERT_EXPIRED
if self.expiration_date - timedelta(days=30) <= now < self.expiration_date:
new_state = self.CERT_EXPIRING
elif now < self.expiration_date - timedelta(days=30):
new_state = self.CERT_OK
if need_update and new_state != self.state:
self.state = new_state
self.save(update_fields=['state'])
return new_state