financial_system/financial_system/domain/models.py
2026-06-18 13:21:20 +08:00

116 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from dataclasses import dataclass, field
from datetime import date, time
from typing import Optional
@dataclass(frozen=True)
class LeaveEvent:
"""请假/调休等工时事件key 用于跨天重复记录去重。"""
kind: str
start_text: str
end_text: str
hours: float
@property
def key(self) -> tuple[str, str, str, float]:
return (self.kind, self.start_text, self.end_text, round(self.hours, 4))
@dataclass
class DailyAttendance:
"""单个员工某一天的考勤明细。"""
work_date: date
raw_text: str = ""
first_punch: Optional[time] = None
last_punch: Optional[time] = None
late_minutes: list[int] = field(default_factory=list)
missing_card_count: int = 0
leave_events: list[LeaveEvent] = field(default_factory=list)
punch_overtime_hours: float = 0.0
@property
def leave_hours_in_cell(self) -> float:
return sum(event.hours for event in self.leave_events)
@dataclass
class EmployeeAttendance:
"""员工月度考勤数据,包含汇总字段和每日明细。"""
name: str
attendance_group: str = ""
department: str = ""
employee_no: str = ""
position: str = ""
user_id: str = ""
summary_fields: dict[str, float | str] = field(default_factory=dict)
daily_records: list[DailyAttendance] = field(default_factory=list)
@property
def unique_leave_events(self) -> list[LeaveEvent]:
seen: set[tuple[str, str, str, float]] = set()
result: list[LeaveEvent] = []
for record in self.daily_records:
for event in record.leave_events:
if event.key not in seen:
seen.add(event.key)
result.append(event)
return result
@dataclass(frozen=True)
class EmployeePayConfig:
"""员工工资配置;计算器只关心规则值,不关心这些值来自数据库还是配置文件。"""
salary_mode: str = "monthly"
base_salary: Optional[float] = None
hourly_rate: float = 0.0
piece_quantity: float = 0.0
piece_unit_price: float = 0.0
probation_type: str = "ratio"
probation_ratio: float = 1.0
probation_salary: Optional[float] = None
commission_amount: float = 0.0
overtime_rate: Optional[float] = None
weekend_overtime_rate: Optional[float] = None
holiday_overtime_rate: Optional[float] = None
@dataclass(frozen=True)
class PayrollResult:
"""员工级工资计算结果。"""
employee: EmployeeAttendance
salary_month: str
salary_mode: str
attendance_days: float
absence_days: float
actual_work_hours: float
punch_overtime_hours: float
leave_hours: float
remaining_overtime_hours: float
workday_overtime_hours: float
weekend_overtime_hours: float
holiday_overtime_hours: float
minor_late_count: int
major_late_count: int
penalized_late_count: int
late_deduction: float
missing_card_count: int
missing_card_deduction: float
total_deduction: float
base_salary: Optional[float]
base_pay: Optional[float]
commission_amount: float
overtime_rate: float
weekend_overtime_rate: float
holiday_overtime_rate: float
overtime_pay: float
gross_salary: Optional[float]
net_salary: Optional[float]
note: str = ""