fix: 年度价值报告风险量化按劳动法设定法定上限
- 单条风险estimatedLoss封顶:双倍工资≤11个月(第82条)、经济补偿N≤12个月月薪≤社平3倍(第47条)、违法解除2N≤24个月(第87条) - 年度规避损失按30%规避率打折(非每项风险都演变为实际仲裁) - ROI上限9999% - 前端计算说明同步更新
This commit is contained in:
@@ -15,8 +15,15 @@ function safeDecryptSalary(encrypted: string): number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 社平工资3倍封顶(参照上海2024年度社平工资约12307元/月,3倍≈36921元)
|
||||||
|
* 《劳动合同法》第47条:月工资高于社平3倍的按3倍计,且补偿年限最高12年
|
||||||
|
*/
|
||||||
|
const SOCIAL_AVG_SALARY_3X = 36921
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 风险量化:根据风险类型和员工数据估算预估损失金额
|
* 风险量化:根据风险类型和员工数据估算预估损失金额
|
||||||
|
* 依据《劳动合同法》《劳动法》设定法定上限
|
||||||
* @returns { estimatedLoss, lossRange, deadline }
|
* @returns { estimatedLoss, lossRange, deadline }
|
||||||
*/
|
*/
|
||||||
function estimateRiskCost(
|
function estimateRiskCost(
|
||||||
@@ -24,21 +31,26 @@ function estimateRiskCost(
|
|||||||
employee?: { hireDate: Date; monthlySalary?: string } | null,
|
employee?: { hireDate: Date; monthlySalary?: string } | null,
|
||||||
): { estimatedLoss: number; lossRange: [number, number]; deadline?: Date } {
|
): { estimatedLoss: number; lossRange: [number, number]; deadline?: Date } {
|
||||||
const today = new Date()
|
const today = new Date()
|
||||||
const salary = employee ? safeDecryptSalary(employee.monthlySalary || '0') : 0
|
const rawSalary = employee ? safeDecryptSalary(employee.monthlySalary || '0') : 0
|
||||||
|
// 第47条:高收入者月薪封顶为社平3倍
|
||||||
|
const salary = Math.min(rawSalary, SOCIAL_AVG_SALARY_3X)
|
||||||
const workYears = employee
|
const workYears = employee
|
||||||
? Math.max(0, (today.getFullYear() - employee.hireDate.getFullYear()) +
|
? Math.max(0, (today.getFullYear() - employee.hireDate.getFullYear()) +
|
||||||
(today.getMonth() - employee.hireDate.getMonth()) / 12)
|
(today.getMonth() - employee.hireDate.getMonth()) / 12)
|
||||||
: 0
|
: 0
|
||||||
const n = Math.max(0.5, Math.round(workYears * 2) / 2) // 经济补偿月数,不满半年算0.5
|
// 经济补偿月数:每满1年1个月,不满半年算0.5个月,第47条上限12年
|
||||||
|
const n = Math.min(12, Math.max(0.5, Math.round(workYears * 2) / 2))
|
||||||
|
|
||||||
// 根据风险标题关键词判断类型并估算
|
// 根据风险标题关键词判断类型并估算
|
||||||
const title = risk.title
|
const title = risk.title
|
||||||
|
|
||||||
// 未签合同(>30天):双倍工资
|
// 未签合同(>30天):双倍工资
|
||||||
|
// 《劳动合同法》第82条:超过1个月不满1年未签书面合同,每月支付2倍工资
|
||||||
|
// 超过1年视为已订立无固定期限合同,不再适用双倍工资,故最多罚11个月
|
||||||
if (title.includes('未签合同') && title.includes('天')) {
|
if (title.includes('未签合同') && title.includes('天')) {
|
||||||
const daysMatch = title.match(/(\d+)天/)
|
const daysMatch = title.match(/(\d+)天/)
|
||||||
const days = daysMatch ? parseInt(daysMatch[1]) : 0
|
const days = daysMatch ? parseInt(daysMatch[1]) : 0
|
||||||
const months = Math.ceil(days / 30)
|
const months = Math.min(11, Math.ceil(days / 30)) // 法定上限11个月
|
||||||
const loss = salary * months
|
const loss = salary * months
|
||||||
return {
|
return {
|
||||||
estimatedLoss: loss,
|
estimatedLoss: loss,
|
||||||
@@ -48,8 +60,9 @@ function estimateRiskCost(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 合同到期未续签:经济补偿 N × 月薪
|
// 合同到期未续签:经济补偿 N × 月薪
|
||||||
|
// 《劳动合同法》第47条:N≤12个月,月薪≤社平3倍
|
||||||
if (title.includes('到期') && title.includes('未续签')) {
|
if (title.includes('到期') && title.includes('未续签')) {
|
||||||
const loss = salary * n
|
const loss = salary * n // n已封顶12
|
||||||
return {
|
return {
|
||||||
estimatedLoss: loss,
|
estimatedLoss: loss,
|
||||||
lossRange: [loss, loss * 2], // 可能被认定为违法解除 2N
|
lossRange: [loss, loss * 2], // 可能被认定为违法解除 2N
|
||||||
@@ -79,8 +92,9 @@ function estimateRiskCost(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 三期/工伤/医疗期:违法解除风险 2N
|
// 三期/工伤/医疗期:违法解除风险 2N
|
||||||
|
// 《劳动合同法》第87条:违法解除按第47条标准的2倍赔偿,2N≤24个月
|
||||||
if (title.includes('孕期') || title.includes('哺乳期') || title.includes('工伤') || title.includes('医疗期')) {
|
if (title.includes('孕期') || title.includes('哺乳期') || title.includes('工伤') || title.includes('医疗期')) {
|
||||||
const loss = salary * n * 2
|
const loss = salary * n * 2 // n已封顶12,故2N≤24
|
||||||
return {
|
return {
|
||||||
estimatedLoss: loss,
|
estimatedLoss: loss,
|
||||||
lossRange: [loss, loss * 2],
|
lossRange: [loss, loss * 2],
|
||||||
@@ -1609,9 +1623,11 @@ export async function getAnnualValueReport(orgId: string, year: number) {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// 价值计算
|
// 价值计算
|
||||||
// 1. 规避损失 = 已解决风险的预估损失之和
|
// 1. 规避损失 = 已解决风险的预估损失之和 × 0.3(规避率30%,非每项风险都会演变为实际仲裁)
|
||||||
// 2. 节约工时 = AI 查询 * 0.5h + 合同审查 * 1h + 算薪批次 * 2h + 制度公示 * 1h
|
// 2. 节约工时 = AI 查询 * 0.5h + 合同审查 * 1h + 算薪批次 * 2h + 制度公示 * 1h
|
||||||
// 3. 节约成本 = 节约工时 * 100 元/h(HR 平均时薪)
|
// 3. 节约成本 = 节约工时 * 100 元/h(HR 平均时薪)
|
||||||
|
const RISK_AVOIDANCE_RATE = 0.3 // 规避率:约30%的未处理风险会演变为实际劳动争议
|
||||||
|
const adjustedLossAvoided = Math.round(lossAvoided * RISK_AVOIDANCE_RATE)
|
||||||
const aiTimeSaved = aiConversations * 0.5 + aiReviews * 1.0
|
const aiTimeSaved = aiConversations * 0.5 + aiReviews * 1.0
|
||||||
const payrollTimeSaved = payrollBatches * 2.0
|
const payrollTimeSaved = payrollBatches * 2.0
|
||||||
const policyTimeSaved = policiesPublished * 1.0
|
const policyTimeSaved = policiesPublished * 1.0
|
||||||
@@ -1619,12 +1635,13 @@ export async function getAnnualValueReport(orgId: string, year: number) {
|
|||||||
const timeSaved = Math.round(aiTimeSaved + payrollTimeSaved + policyTimeSaved + contractTimeSaved)
|
const timeSaved = Math.round(aiTimeSaved + payrollTimeSaved + policyTimeSaved + contractTimeSaved)
|
||||||
const costSaved = timeSaved * 100
|
const costSaved = timeSaved * 100
|
||||||
|
|
||||||
// 总价值 = 规避损失 + 节约成本
|
// 总价值 = 规避损失(打折后) + 节约成本
|
||||||
const totalValue = lossAvoided + costSaved
|
const totalValue = adjustedLossAvoided + costSaved
|
||||||
|
|
||||||
// ROI = 总价值 / 系统成本(假设年费 12000 元)
|
// ROI = 总价值 / 系统成本(年费 12000 元),上限 9999%
|
||||||
const systemCost = 12000
|
const systemCost = 12000
|
||||||
const roi = systemCost > 0 ? Math.round((totalValue / systemCost) * 100) : 0
|
const rawRoi = systemCost > 0 ? Math.round((totalValue / systemCost) * 100) : 0
|
||||||
|
const roi = Math.min(rawRoi, 9999)
|
||||||
|
|
||||||
const metrics = {
|
const metrics = {
|
||||||
risksResolved,
|
risksResolved,
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ export default function AnnualValueReport() {
|
|||||||
<div className="space-y-1 text-xs text-gray-600">
|
<div className="space-y-1 text-xs text-gray-600">
|
||||||
<div className="flex items-start gap-1.5">
|
<div className="flex items-start gap-1.5">
|
||||||
<span className="w-1.5 h-1.5 rounded-full bg-safe mt-1 flex-shrink-0" />
|
<span className="w-1.5 h-1.5 rounded-full bg-safe mt-1 flex-shrink-0" />
|
||||||
<span><b>规避损失</b>:已解决风险的预估损失金额之和(基于风险量化模型)</span>
|
<span><b>规避损失</b>:已解决风险的预估损失之和 × 30%规避率(依据《劳动合同法》量化模型,单条上限按法定标准封顶)</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-1.5">
|
<div className="flex items-start gap-1.5">
|
||||||
<span className="w-1.5 h-1.5 rounded-full bg-blue-500 mt-1 flex-shrink-0" />
|
<span className="w-1.5 h-1.5 rounded-full bg-blue-500 mt-1 flex-shrink-0" />
|
||||||
@@ -238,11 +238,15 @@ export default function AnnualValueReport() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-1.5">
|
<div className="flex items-start gap-1.5">
|
||||||
<span className="w-1.5 h-1.5 rounded-full bg-amber-500 mt-1 flex-shrink-0" />
|
<span className="w-1.5 h-1.5 rounded-full bg-amber-500 mt-1 flex-shrink-0" />
|
||||||
<span><b>总价值</b>:规避损失 + 节约成本</span>
|
<span><b>总价值</b>:规避损失(打折后) + 节约成本</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-1.5">
|
<div className="flex items-start gap-1.5">
|
||||||
<span className="w-1.5 h-1.5 rounded-full bg-gray-400 mt-1 flex-shrink-0" />
|
<span className="w-1.5 h-1.5 rounded-full bg-gray-400 mt-1 flex-shrink-0" />
|
||||||
<span><b>ROI</b>:总价值 ÷ 系统年费(¥12,000)× 100%</span>
|
<span><b>ROI</b>:总价值 ÷ 系统年费(¥12,000)× 100%,上限 9999%</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-start gap-1.5">
|
||||||
|
<span className="w-1.5 h-1.5 rounded-full bg-gray-300 mt-1 flex-shrink-0" />
|
||||||
|
<span><b>法定上限</b>:双倍工资≤11个月(第82条)、经济补偿N≤12个月月薪≤社平3倍(第47条)、违法解除2N≤24个月(第87条)</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user