投身烈火
Keep Walking

javascript实现年终奖避税程序

昨天公司发了年终奖,扣了我20%的税…我就操了,肉疼啊…T^T…话说年终奖避税不是没有办法啊,为毛不给整整呢,总觉得肯定有什么不可告人的秘密…

于是我决定写个年终奖避税的程序去去火,不然这口气憋在心里非憋坏了不可…

政策调查

调查了下相关的政策,根据现有个人所得税计税办法,个人薪酬计税有两种方式,一种为月工资(含月奖金)计税,一种为年终奖综合计税。在年终奖综合计税发放过程中,在某些区间会出现税前奖金增加,税后实际收入反而减少的情况。

具体的税收办法是这样的,

月工资计税公式:

  • 应纳税额 = 月工资应纳税所得额 * 适用税率 - 速算扣除数
  • 月工资应纳税所得额 = 计税月工资额 - 个人所得税起征点
  • 个人所得税起征点 = 3500

解释两个概念:

  • 个人所得税起征点
    既税法规定的费用扣除额。
  • 速算扣除数
    速算扣除数并非税法规定,而是根据税法推算出来的一个方便计算的系数。
    税法中关于个税的计算应该是分阶段的。不超过1500元的收3%,超过1500元至4500元的部分收10%,超过4500元至9000元的部分20%… 如果某人扣保险后工资10000,怎么计算呢?10000 = 3500 + 1500 + 3000 + 2000。 其中3500免征;1500按3%,征税45元;3000按10%,征300元;2000按20%,征400元。整个算下来征税745元。这么算很麻烦,所以会计们发明了速算扣除数。税率3%对应速算扣除数为0;税率10%对应速算扣除数为 1500 * (10% - 3%) + 0 = 105;税率20%对应速算扣除数为 4500 * (20% - 10%) + 105 = 555;以此类推,得到级别的速算扣除数。

放上汇总之后的个人所得税税率表,之后会用到:

级数 全月应纳税所得额(元) 税率(%) 速算扣除数
1 0 ~ 1500 3 0
2 1500.01 ~ 4500 10 105
3 4500.01 ~ 9000 20 555
4 9000.01 ~ 35000 25 1005
5 35000.01 ~ 55000 30 2755
6 55000.01 ~ 80000 35 5505
7 80000.01 ~ ∞ 45 13505

年终奖综合计税办法:

纳税人取得全年一次性奖金,单独作为一个月工资、薪金所得计算纳税,并按以下办法计税。

  • (一) 先将雇员当月内取得的全年一次性奖金,除以12个月,按其商数确定适用税率和速算扣除数。 如果在发放年终一次性奖金的当月,雇员当月计税工资额低于税法规定的费用扣除额(个人所得税起征点3500元),应将全年一次性奖金减除”雇员当月计税工资额与费用扣除额的差额”后的余额,按上述办法确定全年一次性奖金的适用税率和速算扣除数。

  • (二) 将雇员个人当月内取得的全年一次性奖金,按第(一)项确定的适用税率和速算扣除数计算征税,计算公式如下:

    1. 如果雇员当月工资薪金所得高于(或等于)税法规定的费用扣除额的,适用公式为: 应纳税额 = 雇员当月取得全年一次性奖金 * 适用税率 - 速算扣除数
    2. 如果雇员当月计税工资额低于税法规定的费用扣除额的,适用公式为: 应纳税额 = (雇员当月取得全年一次性奖金 - 雇员当月计税工资额与费用扣除额的差额) * 适用税率 - 速算扣除数
  • (三) 在一个纳税年度内,对每一个纳税人,该计税办法只允许采用一次。

实例

看过刚才的政策,咱们再来看三个例子:

  • 员工A,月薪2500,年终奖为5000,应缴个税为150,计算过程如下: 先算计税基础,(5000 - (3500 - 2500)) / 12 = 333.33,查税率表,适用3%的税率。 再算应纳所得税,5000 * 3% - 0 = 150,税后所得为 5000 - 150 = 4850。

  • 员工B,月薪9000,年终奖18000,应缴个税为540,计算过程如下: 先算计税基础,18000 / 12 = 1500,查税率表,适用3%的税率。 再算应纳所得税,18000 * 3% - 0 = 540,税后所得为 18000 - 540 = 17460。

  • 员工C,月薪9500,年终奖19000,应缴个税为1795,计算过程更上面一样,计算过程如下: 先算计税基础,19000 / 12 = 1583.3,查税率表,适用10%的税率。 再算应纳所得税,19000 * 10% - 105 = 1795,税后所得为 19000 - 1795 = 17205。

看过之前三个例子你发现了吗?员工C虽然账面上比员工B多拿了1000的年终奖,但是实际所得却比员工B还少…这就是之前咱们说到的那个问题…也是年终奖需要避税的主要原因…

造成这个问题的主要原因,是由于税率虽然按照年终奖的12分之1计算了,但是速算扣除数却没有对应的扩大12倍。

假如速算扣除数也相应扩大12倍,那么年终奖19000的应缴个税为19000 * 10% - 105 * 12 = 640,这样和年终奖18000纳所得税540是不是差异就很小了?

据说之所以没有执行这样的政策,是因为年终奖一般都会超过一个月工资,直接按照个人所得税的税率纳税,肯定是要多缴税的。除以12个月作为计税基础,已经是税务局给予纳税人很大的优惠了,所以速算扣除数不能再给予优惠…

避税

常见的年终奖避税方式是将年终奖拆分,一部分按年终奖综合计税发放,一部分随月工资发放,一般1到2个月发完。

比如,月薪9500,年终奖19000,如果不做拆分直接纳税,应缴个税1795。如果拆分为年终发18000,之后月工资多发1000奖金,年终奖部分应缴个税应为18000 * 3% = 540,工资部分应缴个税(9500 + 1000 - 3500) * 20% - 555 = 845,比按月薪9500缴纳个税多缴了 200,所以总共少缴纳个税1795 - (540 + 200) = 1055

按照这个思路就来设计一个程序,来自动计算怎么拆分最好,能让收入最多。

设计

首先考虑下这个程序的输入输出,输入月工资和年终奖,然后打印出年终奖发多少,剩余的怎么拆分。

然后考虑具体的功能,缴税额计算都有现成的公式,封装成独立的函数就行了。年终奖的拆分应该会出现三种情况:不拆分最优,拆分入一个月最优,拆分入两个月最优。

因为暂时还没想到什么好算法,所以就不考虑性能,先实现了功能再说,用遍历把所有可能的拆分都试一遍,以后在考虑做剪枝。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
var baseQuota = 3500;
var taxQuota = [1500, 4500, 9000, 35000, 55000, 80000];
var taxRat = [0.03, 0.10, 0.20, 0.25, 0.30, 0.35, 0.45];
var taxQuick = [0, 105, 555, 1005, 2755, 5505, 13505];
// 获取不拆分年奖交税总额
function getOnlyBonusTax(yearBonus, monthSalary) {
var tax = 0;
if (monthSalary > baseQuota) {
perMonth = yearBonus / 12;
tax = round(yearBonus * getTaxRat(perMonth) - getTaxQuick(perMonth), 2);
} else {
if (yearBonus < baseQuota - monthSalary) {
tax = 0;
} else {
perMonth = (yearBonus - (baseQuota - monthSalary)) / 10;
tax = (yearBonus - (baseQuota - monthSalary)) * getTaxRat(perMonth) - getTaxQuick(perMonth);
}
}
return tax;
}
// 获取税率等级
function getTaxNum(money){
for (var i = 0, l = taxQuota.length; i < l; i++) {
if (money <= taxQuota[i]) {
return i;
}
}
return i;
}
// 获取税率
function getTaxRat(money){
return taxRat[getTaxNum(money)];
}
// 获取速算扣除数
function getTaxQuick(money) {
return taxQuick[getTaxNum(money)];
}
// 获取平常月交税金额
function getMonthTax(money) {
if (money > baseQuota) {
return getTax(money - baseQuota);
} else {
return 0;
}
}
// 获取年奖平均月交税金额
function getPerMonthTax(money) {
return getTax(money);
}
// 计算个人所得税金额
function getTax(money) {
return round(money * getTaxRat(money) - getTaxQuick(money), 2);
}
// 计算增加的交税金额
function getMonthTaxAdd(monthSalary, addNum) {
var monthAddSalary = monthSalary + addNum;
monthTaxAdd = round(getMonthTax(monthAddSalary) - getMonthTax(monthSalary), 2);
return monthTaxAdd;
}
// 计算金额小数
function round(num, toFix) {
return parseFloat(num.toFixed(toFix), 10);
}
// 获取拆分为一个月交税总额
function getOneMonthBonus(yearBonus, monthSalary) {
var nowBonusTax = getOnlyBonusTax(yearBonus, monthSalary);
for (var i = 1; i < yearBonus; i++) {
var bonusRemain = yearBonus - i;
var monthTaxAdd = getMonthTaxAdd(monthSalary, i);
var bonusTax = round(getOnlyBonusTax(bonusRemain, monthSalary) + monthTaxAdd, 2);
if (bonusTax < nowBonusTax) {
nowBonusTax = bonusTax;
oneMonth = i;
}
}
return {
tax: nowBonusTax,
bonus: i
}
}
// 获取拆分为两个月交税总额
function getTwoMonthBonus(yearBonus, monthSalary) {
var nowBonusTax = getOnlyBonusTax(yearBonus, monthSalary);
for (var i = 1; i < yearBonus; i++) {
var bonusRemain = yearBonus - i;
var monthTaxAdd = getMonthTaxAdd(monthSalary, (i / 2)) * 2;
var bonusTax = round(getOnlyBonusTax(bonusRemain, monthSalary) + monthTaxAdd, 2);
if (bonusTax < nowBonusTax) {
nowBonusTax = bonusTax;
twoMonth = i / 2;
}
}
return {
tax: nowBonusTax,
bonus: i
};
}
function run(yearBonus, monthSalary){
var startTime = (new Date).getTime();
var yearBonusTax = getOnlyBonusTax(yearBonus, monthSalary);
var oneMonthTax = getOneMonthBonus(yearBonus, monthSalary);
var twoMonthTax = getTwoMonthBonus(yearBonus, monthSalary);
var minTax = Math.min(yearBonusTax, oneMonthTax.tax, twoMonthTax.tax);
var bonusRemain = yearBonus - minTax;
if (minTax == yearBonusTax) {
console.log('年终奖发放:' + yearBonus, '第一个月发放:' + 0, '第二个月发放:' + 0, '实际收入:' + bonusRemain);
} else if (minTax == oneMonthTax.tax) {
console.log('年终奖发放:' + (yearBonus - oneMonthTax.bonus), '第一个月发放:' + oneMonthTax.bonus, '第二个月发放:' + 0, '实际收入:' + bonusRemain);
} else if (minTax == twoMonthTax.tax) {
console.log('年终奖发放:' + (yearBonus - (twoMonthTax.bonus * 2)), '第一个月发放:' + twoMonthTax.bonus, '第一个月发放:' + twoMonthTax.bonus, '实际收入:' + bonusRemain);
}
var endTime = (new Date).getTime();
console.log('耗时:' + (endTime - startTime) + 'ms');
}
run(19000, 9500);

ok,这次就先到这里,下次再更新这个程序的优化方案吧。如果不出意外的话,maybe可能大概下周五会更新吧~马上要过年了,这里先祝米娜桑鸡年大吉咯~!\( ̄︶ ̄)/