- 员工花名册管理(加密存储、导入导出) - 薪酬管理(发薪批次、薪酬模版、加班费计算、工资条) - 社保公积金(多城市配置、版本管理、基数调整) - 解聘管理(6步流程、证据链、工作交接) - AI 助手(合同审查、风险预测、RAG 知识库) - Dashboard 仪表盘 - 设置与通知
18 KiB
社保公积金优化方案
核心原则
- 社保和公积金完全分离:独立配置、独立调基、独立增减员、独立申报
- 社保公积金开始/截止年月必填,增减变以此为准
- 基数缺省等于工资,可修改
- 调薪后社保公积金基数不自动调整(社保基数通常每年7月统一调基,调薪仅影响发薪基数)
- 发薪列表和社保/公积金申报列表中,入离职日期与社保公积金年月不一致时提醒
- 所有变更(入职/重新入职/调基/调薪/调部门/离职/解聘)都按版本记录保存,算薪和月度处理时按月份获取当前有效版本
一、Schema 改动
1.1 拆分配置模型
现有 SocialInsuranceConfig(含社保+公积金比例)拆为:
SocialInsuranceConfig(保留,移除公积金字段):养老/医疗/失业/工伤/生育比例 + 社保基数上下限 + 生效月份 + 版本管理 +adjustmentDone标记HousingFundConfig(新增):公积金企业/个人比例 + 公积金基数上下限 + 生效月份 + 版本管理 +adjustmentDone标记(字段结构同社保配置)
Organization 和 Employee 需增加反向关联字段:
- Organization:
housingFundConfigs HousingFundConfig[]、socialInsRecords EmployeeSocialInsRecord[]、housingFundRecords EmployeeHousingFundRecord[]、departmentRecords EmployeeDepartmentRecord[](salaryChangeRecords已存在)- Employee:
socialInsRecords EmployeeSocialInsRecord[]、housingFundRecords EmployeeHousingFundRecord[]、departmentRecords EmployeeDepartmentRecord[](salaryChanges已存在)
1.2 新增模型:社保/公积金缴费记录(按版本保存)
社保和公积金的基数、起止年月不是 Employee 上的简单字段,而是按版本记录保存。每次入职/重新入职/调基/离职/解聘都生成新版本,形成完整变更历史。
EmployeeSocialInsRecord(社保缴费记录)
model EmployeeSocialInsRecord {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
employeeId String
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
startMonth String // 开始缴费年月 YYYY-MM
endMonth String? // 截止缴费年月 YYYY-MM(null=至今有效)
base Float // 缴费基数
// 变更来源
changeType String // ONBOARDING=入职, REHIRE=重新入职, ADJUST=调基, TERMINATION=离职/解聘
changeRefId String? // 关联的 TerminationRecord ID(离职/解聘时)
remark String?
createdBy String
createdAt DateTime @default(now())
@@index([orgId, employeeId])
@@index([employeeId, startMonth, endMonth]) // 复合索引:按员工+月份查询有效版本
}
EmployeeHousingFundRecord(公积金缴费记录)
model EmployeeHousingFundRecord {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
employeeId String
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
startMonth String // 开始缴费年月 YYYY-MM
endMonth String? // 截止缴费年月 YYYY-MM(null=至今有效)
base Float // 缴费基数
// 变更来源
changeType String // ONBOARDING=入职, REHIRE=重新入职, ADJUST=调基, TERMINATION=离职/解聘
changeRefId String? // 关联的 TerminationRecord ID(离职/解聘时)
remark String?
createdBy String
createdAt DateTime @default(now())
@@index([orgId, employeeId])
@@index([employeeId, startMonth, endMonth]) // 复合索引:按员工+月份查询有效版本
}
Employee 保留便捷字段(当前生效值,由后端同步维护)
socialInsStartMonth String? // 当前社保开始年月(=最新记录的startMonth)
socialInsBase Float? // 当前社保基数(=最新记录的base)
socialInsEndMonth String? // 当前社保截止年月(=最新记录的endMonth,null=在保)
housingFundStartMonth String? // 当前公积金开始年月
housingFundBase Float? // 当前公积金基数
housingFundEndMonth String? // 当前公积金截止年月
这些字段是冗余的便捷查询字段,由后端在创建/更新缴费记录时自动同步。增减员和在职申报查询主要使用 Record 表,发薪计算使用 Employee 便捷字段。
1.3 TerminationRecord 增加字段
socialInsEndMonth String // 社保截止缴费年月 YYYY-MM(必填)
housingFundEndMonth String // 公积金截止缴费年月 YYYY-MM(必填)
TerminationRecord 保存截止年月的同时,后端自动创建一条 EmployeeSocialInsRecord / EmployeeHousingFundRecord,将上一条有效记录的 endMonth 设为此值,并同步 Employee 便捷字段。
1.4 扩展模型:调薪/调部门按版本保存
调薪和调部门也按版本记录保存,与社保公积金缴费记录同理。每次变更生成新版本,算薪和社保公积金月度处理时获取当前最新版。
扩展现有 SalaryChangeRecord(增加版本字段)
现有 SalaryChangeRecord 已有 oldSalary/newSalary/effectiveDate/reason,与其新建模型,直接扩展:
// 在现有 SalaryChangeRecord 增加字段:
effectiveMonth String // 生效年月 YYYY-MM(从 effectiveDate 转换)
endMonth String? // 失效年月 YYYY-MM(null=至今有效,被新版本覆盖时设置)
changeType String @default("SALARY_CHANGE") // ONBOARDING=入职, REHIRE=重新入职, SALARY_CHANGE=调薪
@@index([employeeId, effectiveMonth, endMonth]) // 复合索引
不新建
EmployeeSalaryRecord,直接复用SalaryChangeRecord,避免数据分散。入职时也创建一条(oldSalary=0, newSalary=月薪, changeType=ONBOARDING)。
EmployeeDepartmentRecord(部门变更记录,新增模型)
model EmployeeDepartmentRecord {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
employeeId String
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
oldDepartment String // 调整前部门
newDepartment String // 调整后部门
effectiveMonth String // 生效年月 YYYY-MM
endMonth String? // 失效年月 YYYY-MM(null=至今有效)
reason String? // 调部门原因
changeType String // ONBOARDING=入职, REHIRE=重新入职, TRANSFER=调部门
createdBy String
createdAt DateTime @default(now())
@@index([orgId, employeeId])
@@index([employeeId, effectiveMonth, endMonth]) // 复合索引
}
Employee 上的
monthlySalary和department作为便捷字段由后端同步维护。
1.5 PayrollBatchType 增加枚举
SEVERANCE // 补偿金按月发放(无社保,个税按政策处理)
1.6 数据迁移策略
Schema 改动后,需要为现有员工创建初始 Record:
- EmployeeSocialInsRecord:为每个现有员工创建一条,
startMonth= 入职日期年月,endMonth= 已离职员工的离职日期年月(如有),base= 现有socialInsBase或月薪,changeType= 'ONBOARDING' - EmployeeHousingFundRecord:同上,
base= 现有housingFundBase或月薪 - SalaryChangeRecord:为每个现有员工创建一条初始记录,
oldSalary= 0,newSalary= 当前月薪,effectiveMonth= 入职日期年月,endMonth= null - EmployeeDepartmentRecord:为每个现有员工创建一条,
oldDepartment= '',newDepartment= 当前部门,effectiveMonth= 入职日期年月,endMonth= null - 迁移脚本:
npx prisma db push后执行一次性迁移脚本scripts/migrate-records.ts
二、需求1:新增/重新入职填写社保公积金开始年月+基数
前端 AddEmployeeModal
- 新增4个必填字段(2列布局):
- 社保开始年月(type=month,缺省=入职日期年月,可修改)
- 社保基数(type=number,缺省=月薪,可修改)
- 公积金开始年月(type=month,缺省=入职日期年月,可修改)
- 公积金基数(type=number,缺省=月薪,可修改)
- 当入职日期变更时(
handleHireDateChange),自动同步4个缺省值 canSubmit增加这4个字段的必填校验
前端 RehireModal
- 同 AddEmployeeModal,缺省=新入职日期年月
后端
createEmployeeSchema增加socialInsStartMonth、socialInsBase、housingFundStartMonth、housingFundBase(必填)createEmployee存储这些字段到 Employee 便捷字段,同时创建一条EmployeeSocialInsRecord(changeType=ONBOARDING)和一条EmployeeHousingFundRecord(changeType=ONBOARDING)rehireEmployee接收并更新这些字段,同时创建新版本缴费记录(changeType=REHIRE),并将之前有效记录的 endMonth 设为重新入职前一个月
二.5 需求补充:花名册增加调薪/调部门操作
前端花名册列表
- 每行操作区增加「调薪」「调部门」按钮(与「离职」并列)
前端调薪弹窗(SalaryChangeModal)
- 显示:员工姓名、当前月薪、当前部门
- 输入:
- 新月薪(必填,缺省=当前月薪)
- 生效年月(type=month,必填,缺省=当月)
- 调薪原因(选填)
- 提交后:
- 后端创建
SalaryChangeRecord(oldSalary=当前月薪,newSalary=新月薪,effectiveMonth=生效年月, changeType=SALARY_CHANGE) - 将之前有效记录的
endMonth设为生效月前一个月 - 同步
Employee.monthlySalary= 新月薪
- 后端创建
前端调部门弹窗(DepartmentChangeModal)
- 显示:员工姓名、当前部门
- 输入:
- 新部门(必填,缺省=当前部门)
- 生效年月(type=month,必填,缺省=当月)
- 调部门原因(选填)
- 提交后:
- 后端创建
EmployeeDepartmentRecord(oldDepartment=当前部门,newDepartment=新部门,effectiveMonth=生效年月) - 将之前有效记录的
endMonth设为生效月前一个月 - 同步
Employee.department= 新部门
- 后端创建
后端
POST /roster/:id/salary-change— 调薪,创建版本记录 + 同步 EmployeePOST /roster/:id/department-change— 调部门,创建版本记录 + 同步 EmployeeGET /roster/:id/salary-records— 调薪历史GET /roster/:id/department-records— 调部门历史
算薪和社保公积金月度处理
- 算薪时:根据发薪月份获取该月有效的
SalaryChangeRecord(effectiveMonth <= month且endMonth == null 或 >= month),使用该记录的newSalary作为发薪基数 - 社保公积金月度处理时:根据月份获取该月有效的
EmployeeSocialInsRecord/EmployeeHousingFundRecord,使用该记录的base作为缴费基数 - 部门信息:根据月份获取该月有效的
EmployeeDepartmentRecord,用于月度报表中的部门归属 - 调薪与社保基数关系:调薪仅影响发薪基数,不自动调整社保公积金基数。社保公积金基数仅在每年7月统一调基时调整
三、需求2:离职/解聘填写社保公积金截止年月
前端 ResignModal(Roster.tsx)
- 新增2个必填字段:
- 社保截止年月(type=month,缺省=离职日期年月,可修改)
- 公积金截止年月(type=month,缺省=离职日期年月,可修改)
- 当离职日期变更时,自动同步缺省值
canSubmit增加必填校验
前端 Termination.tsx(解聘向导 Step 1)
- 在解聘日期下方增加社保截止年月、公积金截止年月输入
- 缺省=解聘日期年月,可修改
后端
terminationChecklistSchema增加socialInsEndMonth、housingFundEndMonth(必填)createTermination和createResignation存储这些字段到 TerminationRecord- 同时更新 Employee 便捷字段(
socialInsEndMonth、housingFundEndMonth) - 同时创建/更新缴费记录:将当前有效记录的
endMonth设为截止年月,同步 Employee 便捷字段
四、需求3:社保公积金Tab增加月度增减员+在职申报+导出
4.1 前端 SocialInsurance.tsx 改造
增加顶层 Tab 切换:
- 「社保」Tab:社保配置管理 + 社保调基 + 社保月度增减员 + 社保在职申报
- 「公积金」Tab:公积金配置管理 + 公积金调基 + 公积金月度增减员 + 公积金在职申报
每个 Tab 内再分子 Tab:
- 配置管理(现有功能,社保/公积金各自独立)
- 月度增减员
- 在职申报
4.2 月度增减员
后端 API:
GET /social/monthly-changes?month=YYYY-MM— 社保增减员GET /housing/monthly-changes?month=YYYY-MM— 公积金增减员
逻辑(统一使用 Record 表查询,确保历史月份也能查到已离职员工):
- 增员:查
EmployeeSocialInsRecord.startMonth == month(姓名、部门、基数、开始年月、changeType) - 减员:查
EmployeeSocialInsRecord.endMonth == month且changeType == 'TERMINATION'(姓名、部门、基数、截止年月、离职类型) - 支持导出 CSV(前端生成,无需后端依赖)
前端:选择月份 → 显示增员表和减员表(两个表格或折叠分区)→ 导出按钮
4.3 在职申报
后端 API:
GET /social/active-declaration?month=YYYY-MM— 社保在保人员GET /housing/active-declaration?month=YYYY-MM— 公积金在保人员
逻辑(使用 Record 表查询):
- 筛选条件:
EmployeeSocialInsRecord.startMonth <= month且endMonth == null 或 >= month - 返回:姓名、身份证号、部门、社保基数、开始年月、截止年月
- 支持导出 CSV(前端生成,无需后端依赖)
前端:选择月份 → 显示在保人员表格 → 导出按钮
4.4 调基拆分
现有调基操作同时调整社保和公积金基数。改为:
- 社保调基:只调整社保基数,使用
SocialInsuranceConfig的上下限- 将当前有效记录的
endMonth设为调基月前一个月 - 创建新
EmployeeSocialInsRecord(changeType=ADJUST),startMonth=调基月,base=新基数 - 同步 Employee.socialInsBase / socialInsStartMonth
- 将当前有效记录的
- 公积金调基:只调整公积金基数,使用
HousingFundConfig的上下限- 将当前有效记录的
endMonth设为调基月前一个月 - 创建新
EmployeeHousingFundRecord(changeType=ADJUST),startMonth=调基月,base=新基数 - 同步 Employee.housingFundBase / housingFundStartMonth
- 将当前有效记录的
- 两个调基操作独立执行,各自有
adjustmentDone标记
五、需求4:已离职员工按月发放补偿金
后端
PayrollBatchType增加SEVERANCEcalcBatchEntry:当batchType === 'SEVERANCE'时:socialEmp=0、housingEmp=0、socialOrg=0、housingOrg=0(无社保公积金)tax:经济补偿金在当地社平工资3倍以内免征个税,超过部分按单独税率计税。简化处理:tax=0,备注注明「补偿金免征个税(社平3倍以内)」,如超过3倍需手动计算
- 允许
status === 'RESIGNED'的员工加入SEVERANCE批次 - 补偿金发放可设置发放月数(如约定发放6个月),到期后自动标记为已完成
- 也可手动停止发放
前端 Money.tsx
- 批次类型下拉增加「补偿金发放」选项
SEVERANCE批次:员工选择列表包含已离职员工- 输入项简化:只有补偿金金额(baseSalary),无加班/津贴/扣款
- 可设置发放月数
- 工资条显示:社保=0、公积金=0、个税=0(备注:补偿金免征)
六、需求5:日期不一致提醒
发薪列表提醒
在发薪批次详情中,对每个员工检查发薪月份与入离职日期的一致性:
- 发薪月份 < 入职日期年月 → ⚠️ "该员工2025-07入职,当前发薪月份2025-06尚未入职"
- 发薪月份 > 离职日期年月 → ⚠️ "该员工已于2025-06离职,当前发薪月份2025-07已离职"
- 同时也检查社保公积金年月范围,如有不一致也提醒
社保/公积金申报列表提醒
- 增员:
socialInsStartMonth与hireDate年月不一致 → ⚠️ "社保开始年月与入职日期不一致" - 减员:
socialInsEndMonth与terminationDate年月不一致 → ⚠️ "社保截止年月与离职日期不一致" - 在职申报:
hireDate年月与socialInsStartMonth不一致、terminationDate年月与socialInsEndMonth不一致 → ⚠️ 提醒
七、实施顺序
| 步骤 | 内容 | 涉及 |
|---|---|---|
| 1 | Schema 改动(拆分配置、新增缴费/部门记录模型、扩展SalaryChangeRecord、增加字段、增加枚举)+ prisma db push |
后端 |
| 1.5 | 数据迁移脚本:为现有员工创建初始 Record | 后端 |
| 2 | 后端:createEmployee/rehireEmployee 接收社保公积金字段 + 创建缴费记录版本 |
后端 |
| 3 | 后端:createTermination/createResignation 接收截止年月 + 更新缴费记录版本 |
后端 |
| 3.5 | 后端:调薪/调部门 API + 创建/扩展版本记录 + 同步 Employee | 后端 |
| 4 | 前端:AddEmployeeModal 增加社保公积金输入 | 前端 |
| 5 | 前端:RehireModal 同步 | 前端 |
| 6 | 前端:ResignModal 增加截止年月 | 前端 |
| 6.5 | 前端:花名册增加调薪/调部门弹窗 | 前端 |
| 7 | 前端:Termination.tsx 解聘向导增加截止年月 | 前端 |
| 8 | 后端:月度增减员 + 在职申报 API | 后端 |
| 9 | 后端:SEVERANCE 批次类型 + calcBatchEntry 修改 |
后端 |
| 10 | 前端:SocialInsurance.tsx 改造(Tab拆分+增减员+申报+导出) | 前端 |
| 11 | 前端:Money.tsx 增加补偿金批次 | 前端 |
| 12 | 前端:日期不一致提醒 | 前端 |
| 13 | 编译验证 + git 推送 | 全部 |