16 KiB
16 KiB
工资服务
**本文引用的文件** - [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py) - [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py) - [backend/app/models/models.py](file://backend/app/models/models.py) - [backend/app/schemas/schemas.py](file://backend/app/schemas/schemas.py) - [backend/app/services/assessment_service.py](file://backend/app/services/assessment_service.py) - [backend/app/services/staff_service.py](file://backend/app/services/staff_service.py) - [backend/app/core/database.py](file://backend/app/core/database.py) - [backend/app/core/config.py](file://backend/app/core/config.py) - [backend/init_db.py](file://backend/init_db.py)目录
简介
本文件面向“工资服务”的开发与维护,围绕 SalaryService 类的实现架构展开,系统性阐述以下内容:
- 绩效奖金计算算法:基础工资、绩效系数、考核等级对应的奖金计算逻辑
- 工资记录的数据结构、字段含义与业务规则
- 批量生成工资记录的机制:按月度、季度或年度的计算流程
- 与考核服务、员工服务的集成关系与数据一致性保障
- 异常处理、事务管理与性能优化策略
- 实际计算示例与边界条件处理
项目结构
后端采用分层架构:API 层负责路由与鉴权,Service 层封装业务逻辑,Model 层定义数据模型,Schema 层定义输入输出结构。工资服务位于 Service 层,与考核服务、员工服务协作,最终落库到 SalaryRecord。
graph TB
API["API 路由<br/>salary.py"] --> SVC["服务层<br/>salary_service.py"]
SVC --> MODEL["模型层<br/>models.py 中的 SalaryRecord/Assessment/Staff"]
SVC --> SCHEMA["Schema 定义<br/>schemas.py"]
SVC --> ASSESS_SVC["考核服务<br/>assessment_service.py"]
SVC --> STAFF_SVC["员工服务<br/>staff_service.py"]
SVC --> DB["数据库连接<br/>database.py"]
DB --> CONF["配置<br/>config.py"]
图表来源
- backend/app/api/v1/salary.py
- backend/app/services/salary_service.py
- backend/app/models/models.py
- backend/app/schemas/schemas.py
- backend/app/services/assessment_service.py
- backend/app/services/staff_service.py
- backend/app/core/database.py
- backend/app/core/config.py
章节来源
- backend/app/api/v1/salary.py
- backend/app/services/salary_service.py
- backend/app/models/models.py
- backend/app/schemas/schemas.py
- backend/app/services/assessment_service.py
- backend/app/services/staff_service.py
- backend/app/core/database.py
- backend/app/core/config.py
核心组件
- 工资服务(SalaryService):提供查询、创建、更新、生成、确认、批量生成与批量确认等能力;核心算法集中在绩效奖金计算与总工资汇总。
- 工资记录模型(SalaryRecord):持久化存储工资条目,包含基础工资、绩效得分、绩效奖金、扣款、补贴、应发工资、状态等字段。
- 考核服务(AssessmentService):提供考核的创建、提交、审核、确认等流程,为工资生成提供“已确认”的考核数据。
- 员工服务(StaffService):提供员工信息查询与维护,为工资生成提供基础工资与绩效系数。
- API 路由(salary.py):对外暴露查询、生成、确认、批量生成与批量确认等接口,并进行权限校验。
章节来源
- backend/app/services/salary_service.py
- backend/app/models/models.py
- backend/app/services/assessment_service.py
- backend/app/services/staff_service.py
- backend/app/api/v1/salary.py
架构总览
工资服务的调用链路如下:前端请求经 API 路由进入,由 SalaryService 执行业务逻辑;若需要从考核生成,则联动 AssessmentService 与 StaffService;最终写入数据库并返回结果。
sequenceDiagram
participant FE as "前端"
participant API as "API 路由<br/>salary.py"
participant SVC as "服务层<br/>salary_service.py"
participant ASSESS as "考核服务<br/>assessment_service.py"
participant STAFF as "员工服务<br/>staff_service.py"
participant DB as "数据库"
FE->>API : "POST /salary/generate"
API->>SVC : "generate_from_assessment(staff_id, year, month)"
SVC->>DB : "查询员工信息"
DB-->>SVC : "Staff"
SVC->>DB : "查询已确认考核"
DB-->>SVC : "Assessment(finalized)"
SVC->>SVC : "calculate_performance_bonus()"
SVC->>DB : "插入 SalaryRecord"
DB-->>SVC : "返回新记录"
SVC-->>API : "返回记录ID"
API-->>FE : "生成成功"
图表来源
- backend/app/api/v1/salary.py
- backend/app/services/salary_service.py
- backend/app/services/assessment_service.py
- backend/app/services/staff_service.py
组件详解
工资记录数据模型与字段语义
- 表名:salary_records
- 字段与含义(节选):
- staff_id:员工ID
- period_year / period_month:所属周期(年/月)
- base_salary:基本工资
- performance_score:绩效得分
- performance_bonus:绩效奖金
- allowance:补贴
- deduction:扣款
- total_salary:应发工资(base_salary + performance_bonus + allowance - deduction)
- status:状态(默认 pending,支持 confirmed)
- remark:备注
- created_at / updated_at:创建与更新时间
业务规则:
- 总工资由服务层在创建/更新时计算并入库
- 状态仅允许在“pending”状态下进行更新与确认
- 生成工资记录前需确保同一员工当月无重复记录
章节来源
绩效奖金计算算法
- 奖金基数:PERFORMANCE_BASE(静态常量)
- 计算公式:奖金 = 奖金基数 × (绩效得分/100) × 员工绩效系数
- 输入来源:
- 绩效得分:来自已确认的 Assessment.weighted_score
- 绩效系数:来自 Staff.performance_ratio
- 输出:performance_bonus,用于后续总工资计算
flowchart TD
Start(["开始"]) --> LoadAssess["加载已确认考核<br/>Assessment.finalized"]
LoadAssess --> LoadStaff["加载员工信息<br/>Staff.performance_ratio"]
LoadStaff --> CalcBonus["计算奖金<br/>奖金 = 奖金基数 × 得分/100 × 系数"]
CalcBonus --> SumTotal["汇总总工资<br/>总工资 = 基本工资 + 奖金 + 补贴 - 扣款"]
SumTotal --> Persist["持久化 SalaryRecord"]
Persist --> End(["结束"])
图表来源
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
章节来源
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
工资记录生成与批量处理机制
- 单条生成:generate_from_assessment
- 校验员工存在
- 查询当期“已确认”的 Assessment
- 检查是否存在重复工资记录
- 计算奖金与总工资
- 插入 SalaryRecord(状态 pending)
- 批量生成:batch_generate_for_department
- 基于部门与周期,查询所有“已确认”的 Assessment
- 对每个评估逐条调用单条生成
- 批量确认:batch_confirm
- 按年/月筛选 pending 状态的记录
- 可选按部门过滤
- 将状态置为 confirmed 并返回确认数量
sequenceDiagram
participant API as "API 路由"
participant SVC as "SalaryService"
participant DB as "数据库"
API->>SVC : "batch_generate_for_department(dept_id, year, month)"
SVC->>DB : "查询已确认考核(按部门+周期)"
DB-->>SVC : "Assessments 列表"
loop 遍历每个 Assessment
SVC->>SVC : "generate_from_assessment()"
SVC->>DB : "插入 SalaryRecord"
end
SVC-->>API : "返回生成的记录列表"
图表来源
章节来源
- backend/app/api/v1/salary.py
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
与考核服务、员工服务的集成关系
- 与考核服务(AssessmentService):
- 生成工资记录的前提是存在“已确认”的 Assessment
- 通过 Assessment.status == "finalized" 进行筛选
- 与员工服务(StaffService):
- 读取员工的基础工资与绩效系数
- 作为奖金计算的输入参数
- 数据一致性:
- 生成前检查重复记录,避免重复发薪
- 仅对 pending 状态的记录允许更新与确认
章节来源
- backend/app/services/salary_service.py
- backend/app/services/assessment_service.py
- backend/app/services/staff_service.py
API 接口与权限控制
- 查询列表与详情:普通用户可访问
- 创建、更新、单条生成、确认:需要管理员或经理权限
- 批量生成、批量确认:需要管理员或经理权限
- 返回格式遵循统一响应结构(code/message/data)
章节来源
依赖关系分析
- SalaryService 依赖:
- SQLAlchemy 异步会话(AsyncSession)
- 模型:SalaryRecord、Staff、Assessment
- Schema:SalaryRecordCreate、SalaryRecordUpdate
- 服务:AssessmentService、StaffService
- 外部依赖:
- 数据库连接与事务管理(database.py)
- 应用配置(config.py)
classDiagram
class SalaryService {
+get_list(...)
+get_by_id(...)
+create(...)
+update(...)
+calculate_performance_bonus(...)
+generate_from_assessment(...)
+batch_generate_for_department(...)
+confirm(...)
+batch_confirm(...)
}
class AssessmentService {
+get_by_id(...)
+finalize(...)
}
class StaffService {
+get_by_id(...)
}
class SalaryRecord
class Staff
class Assessment
SalaryService --> AssessmentService : "查询已确认考核"
SalaryService --> StaffService : "读取员工信息"
SalaryService --> SalaryRecord : "创建/更新"
SalaryService --> Staff : "读取基础工资/系数"
SalaryService --> Assessment : "读取加权得分"
图表来源
- backend/app/services/salary_service.py
- backend/app/services/assessment_service.py
- backend/app/services/staff_service.py
- backend/app/models/models.py
章节来源
- backend/app/services/salary_service.py
- backend/app/services/assessment_service.py
- backend/app/services/staff_service.py
- backend/app/models/models.py
性能考量
- 数据库连接池与并发:
- 配置文件提供数据库连接池大小与溢出参数,建议结合业务峰值合理设置
- 查询优化:
- SalaryRecord 与 Assessment 均具备按 staff_id、period、status 的索引,有利于分页与筛选
- 批量生成时建议按部门分批处理,避免一次性加载过多记录
- 事务与回滚:
- 数据库会话在异常时自动回滚,确保数据一致性
- I/O 与序列化:
- API 层对响应进行统一包装,注意避免在高频接口中进行大量对象转换
章节来源
- backend/app/core/config.py
- backend/app/core/database.py
- backend/app/models/models.py
- backend/app/services/salary_service.py
故障排查指南
- 无法生成工资记录
- 检查是否存在“已确认”的 Assessment
- 检查是否已存在同员工/同周期的工资记录
- 检查员工是否存在且基础工资/绩效系数有效
- 更新失败
- 仅允许对状态为“pending”的记录进行更新
- 确认失败
- 仅允许对状态为“pending”的记录进行确认
- 批量生成/确认
- 确认年/月参数正确
- 如指定部门,确认部门ID有效
- 数据库异常
- 查看会话依赖的回滚逻辑是否触发
- 检查连接池配置与数据库可用性
章节来源
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
- backend/app/services/salary_service.py
- backend/app/api/v1/salary.py
- backend/app/core/database.py
结论
SalaryService 提供了完整的工资核算闭环:从“已确认”的考核数据出发,结合员工基础信息,计算绩效奖金并生成工资记录;支持单条与批量生成、单条与批量确认,并通过严格的权限控制与状态约束保障业务正确性。配合合理的数据库索引与连接池配置,可在高并发场景下保持稳定与高效。
附录
实际计算示例与边界条件
- 示例场景
- 员工基础工资:10000,绩效系数:1.2
- 考核加权得分:90
- 奖金基数:3000
- 计算过程:奖金 = 3000 × (90/100) × 1.2;总工资 = 基础工资 + 奖金 + 补贴 - 扣款
- 边界条件
- 绩效得分/系数为 0:奖金为 0
- 补贴/扣款为负:不合法,应在输入层约束
- 已存在同周期记录:拒绝重复生成
- 非“已确认”考核:拒绝生成
- 非“pending”状态:拒绝更新/确认
章节来源