You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

8.2 KiB

薪资计算能力规格

Purpose

为已登录求职者提供基于城市当前政策、用户显式覆盖和个人综合所得累计预扣法的到手工资估算能力。

ADDED Requirements

Requirement: 仅已登录 STUDENT 可访问薪资计算模块

The system SHALL 要求薪资城市查询、计算和历史接口均通过 JWT 认证,并且当前用户必须具有 STUDENT 角色。未认证请求 MUST 返回 401;已认证但非 STUDENT 的请求 MUST 返回 403。

Scenario: 未登录访问城市列表

  • WHEN 客户端未携带有效访问令牌调用 GET /salary-calculator/cities
  • THEN 系统返回 401,且不返回任何城市政策数据

Scenario: 企业用户调用计算接口

  • WHEN 已登录的 COMPANY 用户调用 POST /salary-calculator/calculations
  • THEN 系统返回 403,且不创建历史记录

Requirement: 查询当前启用的城市政策目录

The system SHALL 提供城市列表和城市详情接口。城市列表 MUST 只返回 enabled=true 的城市摘要,并按省份编码、城市编码稳定排序;城市详情 MUST 返回城市元数据、政策版本、生效日期和当前整套默认参数。

Scenario: 获取全部启用城市

  • WHEN STUDENT 调用 GET /salary-calculator/cities
  • THEN 系统按省份编码和城市编码返回所有启用城市摘要,且不包含区县记录

Scenario: 获取城市默认参数

  • WHEN STUDENT 调用 GET /salary-calculator/cities/{cityCode} 且该城市已启用
  • THEN 系统返回六位城市编码、省市名称、政策版本、生效日期、dataLevel、社保和公积金基数上下限、个人比例及大病固定费

Requirement: 城市配置以地级行政区和省直辖县级市为最小单元

The system SHALL 以六位行政区划代码作为城市政策主键,覆盖中国大陆全部地级行政区、直辖市和省直辖县级市,不拆分区县,不包含港澳台。

Scenario: 直辖市使用一条配置

  • WHEN 客户端查询北京市或重庆市
  • THEN 系统返回单一城市级配置,而不是按区县返回多条配置

Scenario: 市内存在分区差异

  • WHEN 同一地级市不同区县存在政策差异
  • THEN 系统仍只使用该地级市的一条当前配置,并在估算声明中提示结果可能受同城差异影响

Requirement: 校验城市政策版本和元数据

The system SHALL 要求每条城市政策具有唯一的六位编码、非空且不晚于采集截止日的生效日期、非空政策版本、合法参数以及 dataLevel。CITY 表示已核验的城市级参数;PROVINCE_FALLBACK 表示使用所属省级公开参数的近似配置。任何参数或生效日期变化 MUST 同步更新 policyVersion。

Scenario: 客户端使用已失效的政策版本计算

  • WHEN STUDENT 提交的 expectedPolicyVersion 与当前城市版本不一致
  • THEN 系统返回 409/9805,响应包含最新 policyVersion 和 policyEffectiveDate,且不生成历史记录

Scenario: 城市政策种子存在非法参数

  • WHEN V41 中存在上下限倒置、比例超限或缺失必填字段的城市记录
  • THEN 迁移或种子集成测试失败,禁止进入验收

Scenario: 使用省级回退参数的城市

  • WHEN 某目标城市没有可核验的城市级参数,V41 使用所属省级公开参数创建记录
  • THEN 该记录必须标记为 PROVINCE_FALLBACK,城市详情、计算响应和历史快照都必须明确返回该精度等级
  • THEN 系统不得把该记录展示为 CITY 或声称其达到城市级官方精确度

Requirement: 用户覆盖参数优先于城市默认值

The system SHALL 允许用户分别覆盖社保基数、公积金基数、养老比例、医疗比例、失业比例、公积金比例和大病固定费。未覆盖字段 MUST 使用城市默认值;显式覆盖值 MUST 通过城市上下限和全国合理性范围校验。

Scenario: 只覆盖公积金基数

  • WHEN 用户提交新的公积金基数但未提交比例覆盖
  • THEN 系统使用用户公积金基数和城市默认公积金比例,其余项目继续使用城市默认值

Scenario: 覆盖基数超出城市范围

  • WHEN 用户提交低于社保下限的社保基数
  • THEN 系统返回 400/9802,且不生成历史记录

Requirement: 计算个人五险一金和大病固定费

The system SHALL 按社保基数计算个人养老、医疗和失业,按公积金基数计算个人公积金,并按城市或用户覆盖值扣除按月大病固定费。工伤和生育保险、单位缴费和企业总成本 MUST 不计入个人到手工资。

Scenario: 未覆盖任何参数

  • WHEN 用户输入税前月薪且未提供覆盖项
  • THEN 社保基数按税前月薪截断到社保区间,公积金基数按税前月薪截断到公积金区间,各个人项目按对应比例计算

Scenario: 用户将某项比例覆盖为 0

  • WHEN 用户将失业比例覆盖为 0
  • THEN 个人失业扣款为 0,其他项目按各自生效参数计算

Requirement: 使用累计月份和专项附加扣除计算应纳税所得额

The system SHALL 接受 monthIndex(1–12)和月度专项附加扣除。monthIndex MUST 表示本年度当前工资口径下已经累计计税的月份数,并假设前序月份的收入、个人缴费和专项附加扣除与本次输入相同。

Scenario: 首次领薪但自然月为九月

  • WHEN 用户九月首次领薪并提交 monthIndex=1
  • THEN 系统按一个月的累计收入和扣除计算,而不是按九个月计算

Scenario: 累计月份为十二

  • WHEN 用户提交 monthIndex=12
  • THEN 系统按十二个月的相同工资、个人缴费和专项附加扣除推导全年累计口径

Requirement: 按居民个人综合所得累计预扣法计算个税

The system SHALL 使用全国统一的居民个人综合所得年度累进预扣税率表和速算扣除数。基本减除费用 MUST 固定为每月 5,000 元,累计应纳税所得额小于等于 0 时 MUST 按 0 计税,当月税额 MUST 不得为负。

Scenario: 累计应纳税所得额低于起征线

  • WHEN 累计收入扣除个人缴费、专项附加扣除和 5,000 × monthIndex 后不大于 0
  • THEN 累计应纳税额为 0,当月个税为 0

Scenario: 月薪进入更高累计税率档

  • WHEN 累计应纳税所得额超过当前档位上限
  • THEN 系统按完整年度累进税率表计算累计应纳税额,并减去按相同假设推导的累计已预扣税额

Requirement: 输出到手工资和完整计算拆解

The system SHALL 返回税前月薪、城市及政策版本、社保基数、公积金基数、个人养老、个人医疗、个人失业、个人公积金、大病固定费、基本减除费用、专项附加扣除、累计月份、累计与当月计税链路、当月个税和到手工资。响应 MUST 标记 estimate=true。

Scenario: 计算成功

  • WHEN STUDENT 提交合法的城市、政策版本和工资参数
  • THEN 系统返回完整拆解、estimate=true、全国税率版本、城市政策版本与生效日期,并返回可访问的历史 ID

Requirement: 校验工资输入并限制金额精度

The system SHALL 要求税前月薪大于 0 且不超过 10,000,000 元,专项附加扣除在 0–10,000,000 元之间,所有用户金额输入最多两位小数。比例 MUST 使用小数表示,且个人上限为养老 20%、医疗 20%、失业 10%、公积金 12%;大病固定费不得超过 10,000 元/月。

Scenario: 金额超过两位小数

  • WHEN 用户提交 0.001 元的金额字段
  • THEN 系统返回 400/9802,且不执行计算

Requirement: 返回稳定的城市和历史错误语义

The system SHALL 使用 400 表示参数非法,404 表示城市或历史不存在,409 表示幂等或政策版本冲突。9801 MUST 表示城市不存在或停用,9802 MUST 表示参数非法,9803 MUST 表示历史不存在或无权访问,9804 MUST 表示幂等冲突,9805 MUST 表示政策版本冲突。

Scenario: 城市停用

  • WHEN 用户提交已停用城市的计算请求
  • THEN 系统返回 404/9801,且不生成历史记录