提交文件
This commit is contained in:
407
.qoder/repowiki/zh/content/数据模型详解/核心数据模型/工资核算模型.md
Normal file
407
.qoder/repowiki/zh/content/数据模型详解/核心数据模型/工资核算模型.md
Normal file
@@ -0,0 +1,407 @@
|
||||
# 工资核算模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py)
|
||||
- [backend/app/models/finance.py](file://backend/app/models/finance.py)
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py)
|
||||
- [backend/app/schemas/schemas.py](file://backend/app/schemas/schemas.py)
|
||||
- [backend/alembic/versions/001_initial.py](file://backend/alembic/versions/001_initial.py)
|
||||
- [backend/alembic/versions/002_template.py](file://backend/alembic/versions/002_template.py)
|
||||
- [frontend/src/views/salary/Salary.vue](file://frontend/src/views/salary/Salary.vue)
|
||||
- [frontend/src/api/salary.js](file://frontend/src/api/salary.js)
|
||||
- [docs/database.md](file://docs/database.md)
|
||||
- [docs/详细设计文档.md](file://docs/详细设计文档.md)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构概览](#架构概览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排除指南](#故障排除指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文档深入解析医院绩效系统中的工资核算模型,重点围绕SalaryRecord模型的设计理念、实现细节以及与考核系统的集成关系。文档涵盖以下关键内容:
|
||||
- 基本工资、绩效得分、绩效奖金、扣款补贴的计算逻辑
|
||||
- 工资核算的时间周期与状态管理(待处理、已确认)
|
||||
- 应发工资的计算公式与字段约束
|
||||
- 绩效奖金与绩效得分的关系、扣款与补贴的设置规则
|
||||
- 与员工的多对一关系、历史记录的版本控制
|
||||
- 批量核算的性能优化策略
|
||||
- 工资计算示例、异常处理机制与数据准确性验证方法
|
||||
|
||||
## 项目结构
|
||||
后端采用FastAPI + SQLAlchemy异步ORM架构,工资核算功能位于以下模块:
|
||||
- 模型层:定义SalaryRecord、Staff、Assessment等实体及其关系
|
||||
- 服务层:实现工资计算、生成、确认、批量处理等业务逻辑
|
||||
- API层:提供REST接口,支持按考核生成工资、批量生成与确认
|
||||
- 前端:提供工资记录查询、编辑、确认等界面
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "前端"
|
||||
FE_View["Salary.vue<br/>视图组件"]
|
||||
FE_API["salary.js<br/>API封装"]
|
||||
end
|
||||
subgraph "后端"
|
||||
API["salary.py<br/>API路由"]
|
||||
Service["salary_service.py<br/>服务层"]
|
||||
Model["models.py<br/>数据模型"]
|
||||
Schema["schemas.py<br/>数据模式"]
|
||||
DB["数据库<br/>salary_records表"]
|
||||
end
|
||||
FE_View --> FE_API
|
||||
FE_API --> API
|
||||
API --> Service
|
||||
Service --> Model
|
||||
Model --> DB
|
||||
Schema --> API
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L1-L156)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L1-L260)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L205-L231)
|
||||
- [frontend/src/views/salary/Salary.vue](file://frontend/src/views/salary/Salary.vue#L33-L245)
|
||||
- [frontend/src/api/salary.js](file://frontend/src/api/salary.js#L1-L42)
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L1-L156)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L1-L260)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L205-L231)
|
||||
- [frontend/src/views/salary/Salary.vue](file://frontend/src/views/salary/Salary.vue#L33-L245)
|
||||
- [frontend/src/api/salary.js](file://frontend/src/api/salary.js#L1-L42)
|
||||
|
||||
## 核心组件
|
||||
- SalaryRecord模型:存储工资核算结果,包含基本工资、绩效得分、绩效奖金、扣款、补贴、应发工资与状态
|
||||
- Staff模型:员工基本信息与绩效系数,用于绩效奖金计算
|
||||
- Assessment模型:考核记录,提供加权得分作为绩效奖金依据
|
||||
- SalaryService服务:实现工资计算、生成、确认、批量处理等核心逻辑
|
||||
- API路由:提供查询、创建、更新、按考核生成、批量生成与确认等接口
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L205-L231)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L88-L115)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L149-L179)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L14-L260)
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L1-L156)
|
||||
|
||||
## 架构概览
|
||||
工资核算从考核结果出发,通过服务层计算绩效奖金并生成工资记录;前端提供查询与确认操作,后端通过权限控制确保只有管理员或经理可以进行关键操作。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant API as "salary.py"
|
||||
participant Service as "salary_service.py"
|
||||
participant DB as "数据库"
|
||||
Client->>API : POST /salary/generate?staff_id&period_year&period_month
|
||||
API->>Service : generate_from_assessment(staff_id, year, month)
|
||||
Service->>DB : 查询员工信息(Staff)
|
||||
Service->>DB : 查询已确认考核(Assessment.status='finalized')
|
||||
Service->>Service : calculate_performance_bonus(weighted_score, performance_ratio)
|
||||
Service->>DB : 插入SalaryRecord(状态=pending)
|
||||
DB-->>Service : 返回新记录
|
||||
Service-->>API : 返回记录ID
|
||||
API-->>Client : {code,message,data : id}
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L96-L111)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L127-L190)
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L96-L111)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L127-L190)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### SalaryRecord模型设计
|
||||
- 字段定义
|
||||
- 基本工资:base_salary,数值型,精度10位小数2位
|
||||
- 绩效得分:performance_score,数值型,精度5位小数2位
|
||||
- 绩效奖金:performance_bonus,数值型,精度10位小数2位
|
||||
- 扣款:deduction,数值型,精度10位小数2位
|
||||
- 补贴:allowance,数值型,精度10位小数2位
|
||||
- 应发工资:total_salary,数值型,精度10位小数2位
|
||||
- 状态:status,默认"pending"
|
||||
- 时间周期:period_year、period_month
|
||||
- 外键:staff_id,关联员工表
|
||||
- 约束与索引
|
||||
- 外键约束:staff_id -> staff.id
|
||||
- 索引:staff_id、(period_year, period_month)
|
||||
- 关系
|
||||
- 与Staff为多对一关系,支持反向访问salary_records
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Staff {
|
||||
+int id
|
||||
+string employee_id
|
||||
+string name
|
||||
+int department_id
|
||||
+string position
|
||||
+string title
|
||||
+float base_salary
|
||||
+float performance_ratio
|
||||
+string status
|
||||
+datetime hire_date
|
||||
+datetime created_at
|
||||
+datetime updated_at
|
||||
+Assessment[] assessments
|
||||
+SalaryRecord[] salary_records
|
||||
}
|
||||
class SalaryRecord {
|
||||
+int id
|
||||
+int staff_id
|
||||
+int period_year
|
||||
+int period_month
|
||||
+float base_salary
|
||||
+float performance_score
|
||||
+float performance_bonus
|
||||
+float deduction
|
||||
+float allowance
|
||||
+float total_salary
|
||||
+string status
|
||||
+string remark
|
||||
+datetime created_at
|
||||
+datetime updated_at
|
||||
}
|
||||
Staff "1" o-- "*" SalaryRecord : "多对一"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L88-L115)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L205-L231)
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L205-L231)
|
||||
- [backend/alembic/versions/001_initial.py](file://backend/alembic/versions/001_initial.py#L133-L154)
|
||||
- [docs/database.md](file://docs/database.md#L197-L216)
|
||||
- [docs/详细设计文档.md](file://docs/详细设计文档.md#L642-L662)
|
||||
|
||||
### 计算逻辑与公式
|
||||
- 绩效奖金计算
|
||||
- 公式:绩效奖金 = 绩效基数 × (绩效得分/100) × 绩效系数
|
||||
- 绩效基数:固定常量,服务层中定义
|
||||
- 绩效系数:来自员工表的performance_ratio
|
||||
- 应发工资计算
|
||||
- 公式:应发工资 = 基本工资 + 绩效奖金 + 补贴 - 扣款
|
||||
- 该公式在创建与更新工资记录时均会重新计算并持久化
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["开始"]) --> LoadStaff["加载员工信息<br/>获取base_salary, performance_ratio"]
|
||||
LoadStaff --> LoadAssessment["加载已确认考核<br/>获取weighted_score"]
|
||||
LoadAssessment --> CheckExisting{"是否存在同周期工资记录?"}
|
||||
CheckExisting --> |是| ReturnNone["返回空不重复生成"]
|
||||
CheckExisting --> |否| CalcBonus["计算绩效奖金<br/>bonus = 基数 × (score/100) × ratio"]
|
||||
CalcBonus --> CalcTotal["计算应发工资<br/>total = base + bonus + allowance - deduction"]
|
||||
CalcTotal --> CreateRecord["创建SalaryRecord<br/>状态=pending"]
|
||||
CreateRecord --> End(["结束"])
|
||||
ReturnNone --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L71-L74)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L127-L190)
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L71-L74)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L85-L91)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L127-L190)
|
||||
|
||||
### 时间周期与状态管理
|
||||
- 时间周期
|
||||
- 由period_year与period_month共同构成,用于唯一标识某员工的某月工资记录
|
||||
- 数据库层面在salary_records上建立了复合索引(idx_salary_period),提升查询效率
|
||||
- 状态管理
|
||||
- 待处理:pending(默认状态)
|
||||
- 已确认:confirmed(管理员/经理确认后变更)
|
||||
- 已发放:paid(当前服务层未实现,但模型预留字段)
|
||||
- 状态变更流程
|
||||
- 单条确认:调用确认接口,仅当状态为pending时允许变更
|
||||
- 批量确认:按年月筛选pending状态记录,可选择按科室过滤
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 待处理
|
||||
待处理 --> 已确认 : "确认工资"
|
||||
已确认 --> 已发放 : "发放工资"
|
||||
已发放 --> [*]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L222-L231)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L234-L259)
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L218-L219)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L222-L231)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L234-L259)
|
||||
|
||||
### 与员工的多对一关系与历史版本控制
|
||||
- 多对一关系
|
||||
- SalaryRecord.staff_id -> Staff.id,每个工资记录对应唯一员工
|
||||
- Staff.salary_records反向关系,支持按员工查询其历史工资记录
|
||||
- 历史版本控制
|
||||
- 当前版本未实现SalaryRecord的版本号字段;如需版本控制,可在模型中增加version字段并在更新时递增
|
||||
- 绩效计划的版本控制已在其他模型中实现(PerformancePlan.version),可借鉴其模式
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L108-L110)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L205-L231)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L293-L293)
|
||||
|
||||
### 批量核算的性能优化
|
||||
- 批量生成
|
||||
- 服务层先查询指定科室下所有已确认的考核记录,再逐条生成工资记录
|
||||
- 建议在大规模数据场景下:
|
||||
- 使用分批处理(分页查询考核记录)
|
||||
- 异步并发插入(注意数据库连接池与事务边界)
|
||||
- 增加数据库索引覆盖查询条件
|
||||
- 批量确认
|
||||
- 通过SQL查询一次性筛选出待确认记录,减少多次往返
|
||||
- 支持按科室过滤,缩小确认范围
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L192-L219)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L234-L259)
|
||||
|
||||
### 扣款与补贴的设置规则
|
||||
- 扣款与补贴均为数值型字段,支持在创建或更新时设置
|
||||
- 服务层在创建与更新时均会重新计算应发工资:total_salary = base_salary + performance_bonus + allowance - deduction
|
||||
- 建议在业务层增加校验规则:
|
||||
- 扣款与补贴必须非负
|
||||
- 应发工资计算后可进行合理性校验(如不得为负)
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L85-L91)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L114-L120)
|
||||
|
||||
### 绩效奖金与绩效得分的关系
|
||||
- 绩效奖金 = 绩效基数 × (绩效得分/100) × 绩效系数
|
||||
- 绩效得分来自Assessment.weighted_score,状态必须为"finalized"
|
||||
- 绩效系数来自Staff.performance_ratio,不同岗位/级别可设置不同系数
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L71-L74)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L143-L153)
|
||||
|
||||
### API与前端交互
|
||||
- API接口
|
||||
- 列表查询:支持按员工、科室、年份、月份、状态筛选
|
||||
- 详情查询:返回带员工与科室名称的完整信息
|
||||
- 创建/更新:仅允许在待处理状态下更新
|
||||
- 按考核生成:基于已确认考核自动生成工资记录
|
||||
- 批量生成/确认:支持按科室批量生成与批量确认
|
||||
- 前端展示
|
||||
- 列表显示基本工资、绩效得分、绩效奖金、补贴、扣款、应发工资等字段
|
||||
- 提供编辑弹窗,支持更新扣款、补贴、备注等
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L20-L156)
|
||||
- [frontend/src/views/salary/Salary.vue](file://frontend/src/views/salary/Salary.vue#L33-L245)
|
||||
- [frontend/src/api/salary.js](file://frontend/src/api/salary.js#L1-L42)
|
||||
|
||||
## 依赖分析
|
||||
- 模型依赖
|
||||
- SalaryRecord依赖Staff(外键)
|
||||
- Assessment与SalaryRecord通过staff_id间接关联
|
||||
- 服务层依赖
|
||||
- 依赖Staff、Assessment模型进行数据查询与计算
|
||||
- 依赖Pydantic模式进行请求/响应数据校验
|
||||
- API层依赖
|
||||
- 依赖Security中间件进行权限控制(管理员/经理)
|
||||
- 依赖数据库会话进行异步操作
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
SalaryRecord["SalaryRecord模型"] --> Staff["Staff模型"]
|
||||
SalaryService["SalaryService"] --> SalaryRecord
|
||||
SalaryService --> Staff
|
||||
SalaryService --> Assessment["Assessment模型"]
|
||||
API["salary.py"] --> SalaryService
|
||||
API --> Schema["schemas.py"]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L205-L231)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L88-L115)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L149-L179)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L10-L11)
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L14-L15)
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L205-L231)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L88-L115)
|
||||
- [backend/app/models/models.py](file://backend/app/models/models.py#L149-L179)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L10-L11)
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L14-L15)
|
||||
|
||||
## 性能考虑
|
||||
- 查询优化
|
||||
- salary_records表已建立索引:staff_id、(period_year, period_month)
|
||||
- API层使用selectinload预加载关联对象,避免N+1查询
|
||||
- 批量处理
|
||||
- 批量生成与确认采用SQL查询一次性筛选,减少循环调用
|
||||
- 建议在高并发场景下增加数据库连接池配置与事务隔离级别
|
||||
- 数据类型
|
||||
- 使用Numeric类型保证金额精度,避免浮点误差累积
|
||||
|
||||
[本节为通用性能建议,无需特定文件来源]
|
||||
|
||||
## 故障排除指南
|
||||
- 无法生成工资
|
||||
- 检查是否存在已确认的考核记录且状态为"finalized"
|
||||
- 检查是否已存在同周期的工资记录(防止重复生成)
|
||||
- 无法确认工资
|
||||
- 确认记录状态必须为"pending"
|
||||
- 检查权限:仅管理员或经理可执行确认操作
|
||||
- 数据不一致
|
||||
- 更新扣款/补贴后需重新计算应发工资
|
||||
- 核对数据库索引是否生效,避免查询性能问题
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L155-L164)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L224-L226)
|
||||
- [backend/app/api/v1/salary.py](file://backend/app/api/v1/salary.py#L132-L142)
|
||||
|
||||
## 结论
|
||||
SalaryRecord模型通过清晰的字段设计与严格的计算逻辑,实现了从考核到工资的自动化流转。服务层提供了完善的生成、确认与批量处理能力,并通过索引与预加载优化了查询性能。未来可在版本控制、状态扩展(如已发放)与更细粒度的扣款/补贴规则方面进一步增强。
|
||||
|
||||
[本节为总结性内容,无需特定文件来源]
|
||||
|
||||
## 附录
|
||||
|
||||
### 工资计算示例
|
||||
- 输入
|
||||
- 员工:基本工资=10000,绩效系数=1.2
|
||||
- 考核:加权得分=95
|
||||
- 扣款=0,补贴=500
|
||||
- 计算过程
|
||||
- 绩效奖金 = 固定基数 × (95/100) × 1.2
|
||||
- 应发工资 = 10000 + 绩效奖金 + 500 - 0
|
||||
- 输出
|
||||
- 工资记录状态=pending,等待确认
|
||||
|
||||
**章节来源**
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L71-L74)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L172-L173)
|
||||
|
||||
### 数据准确性验证方法
|
||||
- 金额精度:使用Numeric类型,避免浮点误差
|
||||
- 业务规则:在服务层增加校验(扣款/补贴非负、应发工资合理)
|
||||
- 索引验证:确认salary_records索引生效,提升查询性能
|
||||
- 测试覆盖:编写单元测试验证计算逻辑与状态变更流程
|
||||
|
||||
**章节来源**
|
||||
- [backend/alembic/versions/001_initial.py](file://backend/alembic/versions/001_initial.py#L133-L154)
|
||||
- [backend/app/services/salary_service.py](file://backend/app/services/salary_service.py#L85-L91)
|
||||
Reference in New Issue
Block a user