如何在Django的Payslip模型中筛选CWorkAttendance授权出勤记录?
解决方案:筛选授权考勤记录并生成薪资单
Alright, let's break down how to implement this logic step by step. Here's what you need to do:
1. 筛选授权的CWorkAttendance记录
首先,我们要从CWorkAttendance中过滤出所有状态为**授权(AUTHORIZED)**的记录。利用模型中定义的常量可以避免硬编码,让代码更易维护:
from .models import CWorkAttendance # 获取所有授权的考勤记录,同时关联员工表避免N+1查询 authorized_attendances = CWorkAttendance.objects.filter( work_entry_status=CWorkAttendance.AUTHORIZED ).select_related('work_employee')
使用select_related('work_employee')可以一次性加载关联的CEmployees数据,提升查询效率。
2. 按员工分组统计工时数据
薪资单是按员工生成的,所以我们需要对授权考勤记录按员工分组,统计总工作时长、加班时长等核心数据。这里用到Django的聚合函数Sum:
from django.db.models import Sum # 按员工分组,统计总工作秒数(假设work_duration存储的是秒) employee_work_summary = authorized_attendances.values('work_employee').annotate( total_work_seconds=Sum('work_duration') )
注意:如果你的
work_duration存储的是分钟/小时,需要自行转换为秒,方便后续薪资计算。
3. 整合逻辑生成Payslip记录
接下来,我们可以编写一个函数,结合员工的薪资费率(从CEmployees表获取),计算薪资总额并创建Payslip记录。首先需要确保CEmployees模型包含所需的费率字段(你提到要从主表获取,这里假设模型已有这些字段):
补充CEmployees模型(示例)
class CEmployees(models.Model): # 其他员工字段(姓名、工号等) basic_hourly_rate = models.IntegerField() # 基本时薪 ot_hourly_rate = models.IntegerField() # 加班时薪
生成薪资单的核心函数
from datetime import datetime from django.db.models import Sum from .models import CWorkAttendance, Payslip, CEmployees def generate_payslip(employee: CEmployees, from_date: datetime.date): # 筛选该员工在指定起始日期后的所有授权考勤 employee_attendances = CWorkAttendance.objects.filter( work_employee=employee, work_entry_status=CWorkAttendance.AUTHORIZED, work_start_time__gte=from_date ).select_related('work_employee') # 统计总工作秒数,若没有记录则默认0 total_work_seconds = employee_attendances.aggregate(Sum('work_duration'))['work_duration__sum'] or 0 total_work_hours = total_work_seconds // 3600 # 转换为小时 # 计算加班时长(假设每月标准工时为160小时,可根据实际规则调整) standard_monthly_seconds = 160 * 3600 total_ot_seconds = max(0, total_work_seconds - standard_monthly_seconds) basic_work_seconds = total_work_seconds - total_ot_seconds # 从员工表获取费率 basic_rate = employee.basic_hourly_rate ot_rate = employee.ot_hourly_rate # 计算薪资总额 basic_amount = (basic_work_seconds / 3600) * basic_rate ot_amount = (total_ot_seconds / 3600) * ot_rate total_amount = round(basic_amount + ot_amount, 2) # 生成符合要求的薪资单号(MM/YY/自增数) current_month_year = datetime.now().strftime("%m/%y") # 获取当月已生成的薪资单数量,自增编号 monthly_payslip_count = Payslip.objects.filter( payslip_generation_date__month=datetime.now().month, payslip_generation_date__year=datetime.now().year ).count() + 1 # 注意:如果payslip_number要存带斜杠的格式,建议把模型字段改成CharField(max_length=15) payslip_number = f"{current_month_year}/{monthly_payslip_count:04d}" # 示例:08/24/0001 # 创建Payslip记录 payslip = Payslip.objects.create( payslip_number=payslip_number, payslip_employee=employee, payslip_generation_date=datetime.now(), payslip_total_hours=total_work_hours, payslip_from_date=from_date, payslip_total_basic_seconds=basic_work_seconds, payslip_total_ot_seconds=total_ot_seconds, payslip_basic_hourly_rate=basic_rate, payslip_basic_ot_rate=ot_rate, payslip_total_amount=total_amount, payslip_entry_status=Payslip.GENERATED ) return payslip
4. 批量生成薪资单(可选)
如果需要给所有员工批量生成薪资单,可以循环CEmployees的记录,调用上述函数:
def bulk_generate_payslips(from_date: datetime.date): employees = CEmployees.objects.all() for employee in employees: generate_payslip(employee, from_date)
注意事项
- 薪资单号字段调整:当前你的
Payslip模型中payslip_number是IntegerField,但如果要存储MM/YY/自增数这种带斜杠的格式,建议改成CharField(max_length=15),否则会报错。 - 加班规则自定义:上述示例中的加班计算规则是假设每月标准160小时,你可以根据公司实际考勤政策调整逻辑。
- 日期范围优化:如果需要生成指定日期区间的薪资单,可以在
filter中添加work_start_time__lte=to_date参数,限定结束日期。
内容的提问来源于stack exchange,提问作者Unknown Username
相关产品推荐
相关产品推荐

