fix: 个税累计预扣中专项附加扣除改为按月读取实际填报金额

原逻辑用 employee.specialDeduction(便捷字段)× 月数计算累计
专项附加扣除,未按月读取 SpecialDeductionRecord 实际金额。
若员工某月填报/取消专项附加扣除,累计值会不准。

修复:
- 优先按月查询 SpecialDeductionRecord(当年至当月)累加实际金额
- 无按月记录时回退到便捷字段 × 月数(兼容旧数据)
- taxBreakdown 增加 specialDeductionSource 字段标识数据来源

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-16 13:36:02 +08:00
parent ce1670d171
commit 454b3d4b05
4 changed files with 695 additions and 3 deletions
+83 -2
View File
@@ -200,6 +200,8 @@ model Organization {
eSignRecords ESignRecord[]
commissionBonuses CommissionBonus[]
medicalPeriodPolicies MedicalPeriodPolicy[]
socialAccounts SocialAccount[]
socialYearStandards SocialYearStandard[]
// 组织架构 + 审批流
departments Department[]
positions Position[]
@@ -459,6 +461,76 @@ model AuditLog {
// ========== 社保 & 通知 & 附件 ==========
/// 社保/公积金账户(实体化管理,替代原 city 字符串)
model SocialAccount {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
type String // SOCIAL=社保账户, HOUSING=公积金账户
name String // 账户名称,如"北京总公司社保账户"
city String // 参保城市
accountNo String? // 社保登记号 / 公积金单位账号
bankName String? // 公积金开户行(公积金专用)
bankAccount String? // 公积金银行账号(公积金专用)
orgName String? // 缴费主体名称(子公司/分公司名称)
orgCode String? // 缴费主体统一社会信用代码
accountType String? // 公积金账户类型 BASIC=基本, SUPPLEMENTARY=补充
isDefault Boolean @default(false)
status String @default("ACTIVE") // ACTIVE=正常, SUSPENDED=停用
remark String?
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
yearStandards SocialYearStandard[]
socialRecords EmployeeSocialInsRecord[]
housingRecords EmployeeHousingFundRecord[]
monthlyProcesses SocialMonthlyProcess[]
@@unique([orgId, type, name])
@@index([orgId, type, city])
@@index([orgId, type, isDefault])
}
/// 年度标准(替代原 SocialInsuranceConfig / HousingFundConfig
model SocialYearStandard {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
accountId String
account SocialAccount @relation(fields: [accountId], references: [id], onDelete: Cascade)
// 社保比例(type=SOCIAL 时使用)
pensionOrg Float @default(16)
pensionEmp Float @default(8)
medicalOrg Float @default(9.8)
medicalEmp Float @default(2)
unemploymentOrg Float @default(0.5)
unemploymentEmp Float @default(0.5)
injuryOrg Float @default(0.2)
maternityOrg Float @default(0.8)
baseMin Float @default(6326)
baseMax Float @default(33891)
medicalBaseMin Float @default(0)
medicalBaseMax Float @default(0)
extraInsurances Json?
// 公积金比例(type=HOUSING 时使用)
housingOrg Float @default(12)
housingEmp Float @default(12)
effectiveFrom String // 生效月份 YYYY-MM
effectiveTo String? // 失效月份 YYYY-MMnull=当前有效)
isCurrent Boolean @default(true)
adjustmentDone Boolean @default(false)
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([accountId, effectiveFrom])
@@index([accountId, isCurrent])
}
model SocialInsuranceConfig {
id String @id @default(cuid())
orgId String
@@ -877,7 +949,9 @@ model EmployeeSocialInsRecord {
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
employeeId String
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
city String @default("北京") // 参保城市
accountId String? // 关联到 SocialAccount(迁移后非空)
account SocialAccount? @relation(fields: [accountId], references: [id])
city String @default("北京") // 参保城市(兼容旧数据,从 account.city 派生)
startMonth String // 开始缴费年月 YYYY-MM
endMonth String? // 截止缴费年月 YYYY-MMnull=至今有效)
base Float // 缴费基数
@@ -890,6 +964,7 @@ model EmployeeSocialInsRecord {
@@index([orgId, employeeId])
@@index([employeeId, startMonth, endMonth])
@@index([orgId, city])
@@index([accountId])
}
model EmployeeHousingFundRecord {
@@ -898,7 +973,9 @@ model EmployeeHousingFundRecord {
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
employeeId String
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
city String @default("北京") // 参保城市
accountId String? // 关联到 SocialAccount(迁移后非空)
account SocialAccount? @relation(fields: [accountId], references: [id])
city String @default("北京") // 参保城市(兼容旧数据)
startMonth String // 开始缴费年月 YYYY-MM
endMonth String? // 截止缴费年月 YYYY-MMnull=至今有效)
base Float // 缴费基数
@@ -910,6 +987,7 @@ model EmployeeHousingFundRecord {
@@index([orgId, employeeId])
@@index([employeeId, startMonth, endMonth])
@@index([accountId])
}
/// 月度社保/公积金办理记录(标记某月已办理完成,保存快照)
@@ -917,6 +995,8 @@ model SocialMonthlyProcess {
id String @id @default(cuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
accountId String? // 关联到账户(迁移后非空)
account SocialAccount? @relation(fields: [accountId], references: [id])
month String // 办理月份 YYYY-MM
type String // SOCIAL=社保, HOUSING=公积金
status String @default("COMPLETED") // COMPLETED=已办理
@@ -928,6 +1008,7 @@ model SocialMonthlyProcess {
@@unique([orgId, month, type])
@@index([orgId, month])
@@index([accountId, month])
}
model EmployeeDepartmentRecord {