工资表逐人算出社保公积金个人、估算个税与实发,两个核对行兜底,缺项说明不假装
payroll-calcSKILL.md 为准。> **本地运行,零网络、免 API Key、数据不出电脑。**
> 四项诚实承诺:① 算不出就说算不出,绝不编造数字;② 高危动作强制人工确认;③ 幂等断点,绝不重复副作用;④ 全程留痕可审计。
# 工资表计算
工资表最怕的不是算错一行,是**对不上**。表上写着应发 19500,明细各项加总是 18500;
扣了社保公积金又扣了个税,最后实发给员工的是 15236,可谁也说不清差在哪。
本包就干一件事:把「应发 → 社保公积金个人 → 个税 → 实发」这条链算干净,
并在最后给出两条硬核对。
## 算什么
| 环节 | 公式 |
|---|---|
| 应发合计 | = 各项应发之和(表里有明细列时逐行校验) |
| 扣款合计 | = 社保个人 + 公积金个人 + 其他扣款 + 估算个税 |
| 应纳税所得额 | = 应发 − 基本减除费用 − 社保公积金个人 − 专项附加扣除 |
| 估算个税 | 按**月度税率表**快算(估算值,见下方口径说明) |
| 实发工资 | = 应发 − 扣款合计 |
两个核对行:
- **① 应发合计 = 各项之和**——只有表里同时提供了明细列时才核算;
没有明细列就写「不适用」,**不按 0 当通过**。
- **② 实发 = 应发 − 扣款合计**——每行都算差异,合计差异非 0 一律进异常表。
## 输入 / 输出
输入:1 个工资表文件(`.xlsx` / `.csv`),首行表头。
| 列 | 是否必需 | 别名示例 |
|---|---|---|
| 姓名 | 必需 | 姓名 / 员工姓名 / 员工 / 人员 / 职工姓名 |
| 应发工资 | 必需 | 应发工资 / 应发工资合计 / 应发合计 / 应发 / 工资总额 |
| 社保个人 | 可选 | 社保个人 / 社会保险个人 / 个人社保 / 养老个人 |
| 公积金个人 | 可选 | 公积金个人 / 住房公积金个人 / 个人公积金 / 公积金 |
| 专项附加扣除 | 可选 | 专项附加扣除 / 附加扣除 / 专项附加 |
| 其他扣款 | 可选 | 其他扣款 / 代扣款项 / 扣款 |
| 应发明细项 | 可选 | 基本工资 / 岗位工资 / 绩效工资 / 加班工资 / 补贴 / 其他应发 |
| 个人所得税 | 可选 | 个税 / 代扣个税(表里已给个税时仅作对照) |
输出(进 `_out/`,源文件一个字节都不动):
| 文件 | 内容 |
|---|---|
| `pr_主表.csv` | 逐人计算结果(含应纳税所得额、适用税率、速算扣除数) |
| `pr_异常表.csv` | 不可计算行 + 需人工复核项(带行号、风险等级) |
| `pr_校验表.csv` | 起征点、两条核对行差异、个税口径、人工复核声明 |
| `pr_核对行.csv` | ① 应发合计 = 各项之和 ② 实发 = 应发 − 扣款合计 ③ 逐行差异合计 |
| `fin-log.jsonl` | 处理日志(追加) |
## 用法
```bash
PY="<python 3.8+ 路径>" # 纯标准库,无需 pip install
"$PY" <skill目录>/scripts/payroll.py 工资表.xlsx --execute
```
(`/scripts/fin_xlsx_lite.py`、`fin_contract.py` 是随包内核副本,不用单独装)
起征点按当地口径调:
```bash
"$PY" payroll.py 工资表.xlsx --threshold 5000 --execute
```
表里没有社保 / 公积金列时,按应发比例估算个人部分(**是估算,不是申报数**):
```bash
"$PY" payroll.py 工资表.xlsx --insure --social-rate 0.10 --fund-rate 0.12 --execute
```
**默认不写盘**——不加 `--execute` 只打印预览,确认无误再落盘。
## 真实输出
```
已生成:pr_好表_工资表.xlsx / pr_坏表_缺姓名列.xlsx / pr_坏表_各种错.xlsx / pr_坏表_扣款超应发.xlsx
方案:pr_好表_工资表.xlsx(5 行;姓名列「姓名」,应发列「应发工资」)
识别到的应发明细项:基本工资、岗位工资、绩效工资、加班工资、补贴津贴
--- 工资计算结果(共 5 行)---
序号 姓名 应发 社保个人 公积金 估算个税 实发
1 张伟 19500.00 1800.00 1560.00 904.00 15236.00
2 李娜 14600.00 1500.00 1200.00 380.00 11520.00
3 王强 11700.00 1200.00 900.00 250.00 9300.00
4 赵敏 16900.00 1700.00 1400.00 470.00 13330.00
5 陈涛 8500.00 900.00 720.00 56.40 6823.60
--- 核对行(合计口径)---
① 应发合计 = 各项之和:差异 0.00
② 实发 = 应发 − 扣款合计:差异 0.00
--- 异常表:本次未发现异常记录(0 条)---
```
失败路径(不崩溃、不吐假数):
```
$ payroll.py pr_坏表_缺姓名列.xlsx --execute
【算不出】表「pr_坏表_缺姓名列.xlsx」里找不到姓名列
建议:至少要有「姓名」列;别名支持:姓名、员工姓名、员工、人员、职工姓名、员工名字
本包不会给一个看似合理的替代数字 —— 财税场景算错比不做更危险。
$ payroll.py pr_坏表_各种错.xlsx --execute
【算不出】工资表里有 1 个重复的姓名,无法定位唯一员工:第3行与第7行同「王强」
建议:先把重名行合并或改成工号唯一再跑本包
$ payroll.py pr_坏表_应发不可用.xlsx --execute
方案:pr_坏表_应发不可用.xlsx(5 行;姓名列「姓名」,应发列「应发工资」)
识别到的应发明细项:无(不做应发合计核对)
--- 工资计算结果(共 2 行)---
1 张伟 19500.00 1800.00 1560.00 904.00 15236.00
2 陈涛 8500.00 900.00 720.00 56.40 6823.60
--- 核对行(合计口径)---
① 应发合计 = 各项之和:不适用(未提供应发明细列,不按 0 当通过)
② 实发 = 应发 − 扣款合计:差异 0.00
--- 异常表(3 条)---
[第2行 李娜] 应发工资为 0,无法进入计税链条
[第3行 王强] 应发工资为负(-5000.00),通常是冲销行,先查来源
[第4行 赵敏] 应发工资缺失或不是数字,整行不可计算
$ payroll.py pr_坏表_扣款超应发.xlsx --execute
--- 异常表(3 条)---
[第1行 甲员工] 社保公积金个人部分(10400.00)大于应发(10000.00),实发必为负
[第1行 甲员工] 算出的实发为负(-400.00),扣款合计 10400.00 超过应发
[第2行 乙员工] 应发合计(13000.00)≠ 明细各项之和(10000.00),差 3000.00
```
(最后一条里的「应发合计 ≠ 明细各项之和」差异 3000.00 也会同步写进 `pr_核对行.csv` 的核对①。)
## 拒绝权(什么情况下不给数)
| 情况 | 处理 |
|---|---|
| 找不到姓名列 / 应发工资列 | 拒绝(RC=2),列出可识别的别名 |
| 同一姓名出现多行 | 拒绝(RC=2),报出重复的行号 |
| 只有表头没有数据行 | 拒绝(RC=2) |
| `--threshold` 不是数字或为负 | 拒绝(RC=2) |
| 应发缺失 / 为 0 / 为负 | 该行进**异常表**(高风险),整行不参与后续计算 |
| 社保/公积金个人部分为负 | 该行进异常表,方向反了 |
| 扣款合计 > 应发、实发为负 | 该行进异常表(高风险),仍保留在主表可追溯 |
| 应发明细各项之和 ≠ 应发 | 该行进异常表(高风险),核对①同步列出差异 |
缺列不会让本包崩,但会**逐列写明**:没有社保列、没有公积金列、没有专项附加扣除列、
没有其他扣款列时,备注里逐条记一句「某项按 0 记(不影响实发,但个税会多算)」——
不假装「没列 = 没扣 = 没问题」。
## 关键设计(容易踩的坑)
1. **个税是估算值**。本包按**月度税率表**快算,只是给您一个量级参考。
**按累计预扣法,实际个税以申报为准**——累计预扣会把全年收入摊到 12 个月,
中间月份的累计所得额会带着前面的收入一起跳档,跟月度税率表算出来不一样。
2. **应纳税所得额 ≤ 0 时个税记 0,备注写「无需缴税」**。
这一步不进除法,从左到右下不来除零错误,也不会给您一个「0 元但写了税率」的假象。
3. **扣款合计含个税**。所以 `实发 = 应发 − 扣款合计` 一条公式就够,
不需要再减一次个税;想看「不含个税的扣款」看备注列与主表的「扣款合计」即可。
4. **缺列 ≠ 缺钱**。没有社保列时本包按 0 记并说明,而不是当「没扣社保」直接算个税;
需要按比例估算时请用 `--insure`,并明确那是估算。
5. **起征点不自动跟当地政策走**。默认 5000,`--threshold` 按公司实际口径调整。
## 人工复核(必读)
- 个税只是月度税率表估算,**申报数以税局申报结果为准**,差异可能很大
- 社保公积金个人部分按工资表原样取数,**没有核对缴纳基数与工资是否同源**,
实际缴费基数和起缴口径请以社保局申报为准
- 专项附加扣除本包只做减法,不判断您填的额度和填报信息是否一致
- 实发为负的行一定先查扣款方向,别直接拿去发钱
- 应付职工薪酬的账务处理、跨月发放、离职补差等,本包一概不涉及
## 相邻路线转交
| 用户要做的事 | 转交给 |
|---|---|
| 工资表 / 社保表 / 个税申报表三张表按人核对 | `payroll-three-check` |
| 生成可发给员工的工资条 | `salary-slip-gen` |
| 个税专项附加扣除信息核对 | `tax-form-fill` |
| 工资计提、发放凭证入账 | `voucher-batch-generate` |
| 个税申报表填写 | `tax-form-fill` |
## 可直接复制的说法
```text
把我这张工资表跑一遍:应发 → 社保公积金个人 → 个税 → 实发。
应发明细和扣款列缺的,在备注里逐条写明,不要按 0 当没问题。
个税按月度税率表估算就行,但要注明按累计预扣法实际个税以申报为准。
应纳税所得额小于等于 0 的直接写个税 0 并注明「无需缴税」,不要除零、不要给替代值。
最后给我两个核对行:应发合计 = 各项之和,实发 = 应发 − 扣款合计,差异要单独列出来。
重名行、应发为 0 或负的行,标记为不可计算进异常表,不要我自己去猜。
```
## 做完怎么算完成
- [ ] 5 个税级(3%/10%/20%/25%/30%+)的「适用税率 / 速算扣除数」已抽查确认
- [ ] 「① 应发合计 = 各项之和」「② 实发 = 应发 − 扣款合计」两条核对行差异都是 0
- [ ] 缺列说明(社保 / 公积金 / 专项附加 / 其他扣款)已逐条确认符合本司口径
- [ ] 所有「实发为负」「扣款超应发」的行已逐条追查来源
- [ ] 确认了个税只是估算,实际申报以累计预扣法结果为准
---
本 Skill 采用 BUSL-1.1 许可(源码可见,可自由使用)。
版权所有 © 2026 律令科技(深圳)有限公司(@lexord-technology)。
本技能由律令科技(深圳)有限公司开发,**财友云(caiyouyun.cn)**发布与展示。
允许个人及企业内部免费使用、复制、修改,包括内部生产环境。
未经书面许可,不得将本 Skill 或其修改版作为商业服务对外销售、转售或提供托管服务。
各版本发布之日起 4 年后自动转为 Apache License 2.0。详见随包 `LICENSE.md`。增值税/附加/个税/印花税/所得税预缴,附公式与政策依据
金额大写、含税不含税互算、价税分离、尾差分摊、百分比反算
直线/双倍余额/年数总和/工作量法,生成折旧明细表
期间生成、周旬季年切换、工作日调整、账期与自然日换算
按年度-凭证号-附件组织,生成目录清单与完整性校验
按人拆成独立文件,可加密打包,不留明文
无形资产与长期待摊费用摊销明细表
新增/折旧/处置/盘点全生命周期台账
等额本息/等额本金/气球贷,含实际利率与 IRR 校验
多币种折算、期末汇兑损益计算,汇率走内置表或导入
合并查询所有财税技能的运行日志,按时间/技能/级别过滤
银行卡/身份证/税号/账套口令扫描与脱敏报告
SKILL.md 为准。