💀填好个税,一年多给几千块 ~ 聊聊个人所得税,你该退税还是补税?写一个个税的计算器(退税、补税、个税)

106 阅读8分钟

前言

一年一度个税年度综合汇算清缴的时间又到了,作为开发者的你,肯定过了起征点了吧。🫤

去年退税退了 5676 ,今年看这个估计得补好几千,但是个税年度汇算清缴还没有预约到,抓紧提前算算金额,做做心理建设。\同时,了解个税都扣在哪了,才可以让我们合理避税~

下面我们简单聊聊 补税预缴 ,顺便讲讲专项附加扣除应该怎么填。

以及带大家写一个个税计算器。你可以通过码上掘金查看 在线 svelte(无UI) 版 ,后续也会推出其他框架版。

为什么你需要补税?

大多数情况下,公司发工资会替你把税交了,这个行为叫预缴。

为什么预缴呢?因为国家规定:

《个人所得税扣缴申报管理办法(试行)》(国家税务总局公告2018年第61号发布)
第六条:扣缴义务人向居民个人支付工资、薪金所得时,应当按照累计预扣法计算预扣税款,并按月办理扣缴申报。

这也就是我们每个月发工资都会扣税的原因。

那为什么需要补税呢?因为预缴是根据你在当前公司的收入进行缴税,公司会计算你的累进税率,你会发现每到年底税交的越来越高了,这是累进预缴导致的。

有些人在年中换了工作了,新公司不知道你之前已经交到哪个阶段的个税了,因此预缴时计税金额会重新累计。

因此补税的原因不外乎:

  • 工作变更
  • 公司主体变更(如:公司拆分)

为什么说预缴是天才发明?

预缴制简直是个天才发明,不但会大大减少逃税人数,而且能减轻税务工作量(转移至各公司),且可以让缴税的人对税率的感知没有那么强烈。

达成这种效果主要原因有两点,分别是 损失厌恶心理账户

损失厌恶

人们对损失的敏感程度通常远远大于对同等价值的收益的敏感程度
人们对损失的敏感程度通常远远大于对同等价值的收益的敏感程度
人们对损失的敏感程度通常远远大于对同等价值的收益的敏感程度

牢记这句话。

一个最简单的例子,短视频中经常会出现的 最有效的 6 条学习方式,最后一条最重要 。这种放大损失的语言,常常能诱发更高的完播率。

虽然我很讨厌以这种方式留住用户,但常常在刷到这类视频时,也忍不住多看一样,虽然知道它最终可能也没什么实质内容。

还有一种就是我们常常刷掉一个视频,又返回去看一眼,又刷掉又返回去。我常常会有这种心理,这个视频我是不是应该看一看的纠结。

个税也是同理,个税预缴是减少我们的收益,而个税年终汇算则是直接让我们从口袋中掏钱。

就算汇算综合到月度计算,同样也是,一种是公司扣完发给你,另一种是发给你之后你再掏出来一部分。大家感受一下这其中的区别。

心理账户

人们可能会将个税缴纳视作开销,而且是意外开销,意外开销总是让人痛苦的。

比如我每个月 1w 块,其中 3k 拿来租房,3k 拿来吃饭, 2k 拿来娱乐,2k 拿来缴五险一金。

这时候到年终汇算时,人们则容易苦不堪言。

且这种带来的直接后果是,我想把税留到最后一天交,同时最后一天也很容易忘记交,因为大脑也不想要这种意外支出。

最终则导致 漏交、拒交 个税的人数大大增加。

专项附加扣除严谨度

  • 子女教育(未婚,无接触)
  • 赡养老人(容易被查)
  • 继续教育 - 学历提升(基本不查)
    • 学历提升可以选择一个对应学历,每个学历 4 年,共 16 年左右抵税
  • 继续教育 - 证书获取(基本不查)
    • 证书获取有人一个证书可以一直抵税,建议: 营养师证、焊工证等
  • 租房买房(基本不查)
  • 大病医疗(未填过,未知)

开发

首先咱们先写个个税计算器的 class ,个人所得税英文简称 IIT (Individual Income Tas)

class IITCalulator {}

添加需要计算的内容

众所周知,
个税计算法:应缴税款 * 对应税率 - 速算扣除
应缴税款计算法:工资 - 五险一金缴纳额 - 专项附加扣除

因此我们先添加 工资 、 五险一金 、 专项附加扣除 的属性。

工资

我们工资有两个组成部分,分别是 固定工资 和 年终奖(如果有的话)。

class IITCalulator {
  private salary: {
    monthlySalary: number;
    yearEnd: number;
  } = {
    monthlySalary: 0,
    yearEnd: 0,
  };
  
  /**
   * @description 添加工资(通过工资计算年薪)
   */
  addSalary(
    monthlySalary,
    yearEnd?: { value: number; type: "month" | "amount" }
  ) {
    this.salary.monthlySalary = monthlySalary;
    if (yearEnd) {
      this.salary.yearEnd =
        yearEnd.type === "amount"
          ? yearEnd.value
          : monthlySalary * yearEnd.value;
    }
  }
}

五险一金

这里直接给了固定金额,可以通过查看每月扣除得知。

考虑到有人不太清楚自己的五险一金缴纳基数,这里直接用了固定金额,后续可以扩展出通过缴纳比例自动计算

class IITCalulator {
  private socialInsuranceMonthlyAmount = 0;
  
  /**
   * @description 添加五险一金,计算年五险一金缴纳额
   * @param {number} monthlyAmount 月度缴纳金额
   */
  addSocialInsurance(monthlyAmount) {
    this.socialInsuranceMonthlyAmount = monthlyAmount;
  }
}

专项附加扣除

专项附加扣除通过数组的方式存储扣除项。

  1. 子女教育
  2. 赡养老人
  3. 继续教育(学校)
  4. 继续教育(证书)
  5. 住房贷款
  6. 大病医疗
// 专项附加扣除类型
type SpecialDeductionType =
  | "children"
  | "elder"
  | "education-school"
  | "education-certificate"
  | "housing"
  | "medical";
  
class IITCalulator {
  private specialDeductionTypes: Array<SpecialDeductionType> = [];
  private medicalAmount = 0;

  /**
   * @description 添加专项附加扣除
   * @param {string} type 专项附加扣除类型
   */
  addSpecialDeduction(
    SpecialDeductionType: SpecialDeductionType,
    medicalAmount?: number
  ) {
    this.specialDeductionTypes.some((t) => t !== SpecialDeductionType) &&
      this.specialDeductionTypes.push(SpecialDeductionType);

    if (medicalAmount) {
      this.medicalAmount = medicalAmount;
    }
  }
}

计算 工资 、 五险一金 、 专项附加扣除

我们添加了基础属性,可以根据基础属性计算出对应金额。

工资

工资 = 月薪 * 12 + 年终奖

getYearSalary() {
    return this.salary.monthlySalary * 12 + this.salary.yearEnd;
}

五险一金

五险一金 = 月缴纳额 * 12

getYearSocialInsurance() {
    return this.socialInsuranceMonthlyAmount * 12;
}

专项附加扣除

专项附加扣除 = 扣除项的扣除金额合集

需要注意的是:大病扣除项是固定金额的

这里直接采用 reduce 进行累加。

/**
 * @description 计算专项附加扣除
 */
private getSpecialDeduction() {
  return this.specialDeductionTypes.reduce((r, v) => {
    switch (v) {
      case "children":
        return r + 2000 * 12;
      case "elder":
        return r + 3000 * 12;
      case "education-school":
        return r + 400 * 12;
      case "education-certificate":
        return r + 3600;
      case "housing":
        return r + 1500 * 12;
      case "medical":
        return r + this.medicalAmount;
      default:
        return r;
    }
  }, 0);
}

计算纳税金额

我们基础数据都有了,就只差计算了。先通过基础数据计算应纳税所得额,再通过应纳税所得额计算个税。

计算应纳税所得额

calcIIT() {
  // 计算年薪
  const yearSalary = this.getYearSalary();
  // 五险一金缴纳金额
  const yearSocialInsurance = this.getYearSocialInsurance();
  // 专项附加扣除金额
  const specialDeduction = this.getSpecialDeduction();
  // 计算需要缴纳个税的金额
  let taxableAmount =
    yearSalary - yearSocialInsurance - specialDeduction - 60000;
  // 计算个税
  return this.calcTaxableAmount(taxableAmount);
}

计算应缴个税

个税计算参考:

image.png

// 计算个税(金额 * 税率 - 速算扣除)
private calcTaxableAmount(taxableAmount: number) {
  if (taxableAmount <= 36000) {
    return taxableAmount * 0.03;
  } else if (taxableAmount <= 144000) {
    return taxableAmount * 0.1 - 2520;
  } else if (taxableAmount <= 300000) {
    return taxableAmount * 0.2 - 16920;
  } else if (taxableAmount <= 420000) {
    return taxableAmount * 0.25 - 31920;
  } else if (taxableAmount <= 660000) {
    return taxableAmount * 0.3 - 52920;
  } else if (taxableAmount <= 960000) {
    return taxableAmount * 0.35 - 85920;
  } else {
    return taxableAmount * 0.45 - 181920;
  }
}

完整代码:

// 专项附加扣除类型
// 1. 子女教育
// 2. 赡养老人
// 3. 继续教育(学校)
// 4. 继续教育(证书)
// 5. 住房贷款
// 6. 大病医疗
type SpecialDeductionType =
  | "children"
  | "elder"
  | "education-school"
  | "education-certificate"
  | "housing"
  | "medical";

class IITCalculator {
  private salary: {
    monthlySalary: number;
    yearEnd: number;
  } = {
    monthlySalary: 0,
    yearEnd: 0,
  };
  private socialInsuranceMonthlyAmount = 0;

  private specialDeductionTypes: Array<SpecialDeductionType> = [];
  private medicalAmount = 0;

  constructor() {}

  /**
   * @description 添加工资(通过工资计算年薪)
   */
  addSalary(
    monthlySalary,
    yearEnd?: { value: number; type: "month" | "amount" }
  ) {
    this.salary.monthlySalary = monthlySalary;
    if (yearEnd) {
      this.salary.yearEnd =
        yearEnd.type === "amount"
          ? yearEnd.value
          : monthlySalary * yearEnd.value;
    }
  }

  getYearSalary() {
    return this.salary.monthlySalary * 12 + this.salary.yearEnd;
  }

  /**
   * @description 添加五险一金,计算年五险一金缴纳额
   * @param {number} monthlyAmount 月度缴纳金额
   */
  addSocialInsurance(monthlyAmount) {
    this.socialInsuranceMonthlyAmount = monthlyAmount;
  }

  getYearSocialInsurance() {
    return this.socialInsuranceMonthlyAmount * 12;
  }

  /**
   * @description 添加专项附加扣除
   * @param {string} type 专项附加扣除类型
   */
  addSpecialDeduction(
    SpecialDeductionType: SpecialDeductionType,
    medicalAmount?: number
  ) {
    this.specialDeductionTypes.some((t) => t !== SpecialDeductionType) &&
      this.specialDeductionTypes.push(SpecialDeductionType);

    if (medicalAmount) {
      this.medicalAmount = medicalAmount;
    }
  }

  /**
   * @description 计算专项附加扣除
   */
  private getSpecialDeduction() {
    return this.specialDeductionTypes.reduce((r, v) => {
      switch (v) {
        case "children":
          return r + 2000 * 12;
        case "elder":
          return r + 3000 * 12;
        case "education-school":
          return r + 400 * 12;
        case "education-certificate":
          return r + 3600;
        case "housing":
          return r + 1500 * 12;
        case "medical":
          return r + this.medicalAmount;
        default:
          return r;
      }
    }, 0);
  }

  calcIIT() {
    // 计算年薪
    const yearSalary = this.getYearSalary();
    // 年终奖是否单独计税

    // 五险一金缴纳金额
    const yearSocialInsurance = this.getYearSocialInsurance();
    // 专项附加扣除金额
    const specialDeduction = this.getSpecialDeduction();
    // 计算需要缴纳个税的金额
    let taxableAmount =
      yearSalary - yearSocialInsurance - specialDeduction - 60000;
    // 计算个税
    return this.calcTaxableAmount(taxableAmount);
  }

  // 计算个税(金额 * 税率 - 速算扣除)
  private calcTaxableAmount(taxableAmount: number) {
    if (taxableAmount <= 36000) {
      return taxableAmount * 0.03;
    } else if (taxableAmount <= 144000) {
      return taxableAmount * 0.1 - 2520;
    } else if (taxableAmount <= 300000) {
      return taxableAmount * 0.2 - 16920;
    } else if (taxableAmount <= 420000) {
      return taxableAmount * 0.25 - 31920;
    } else if (taxableAmount <= 660000) {
      return taxableAmount * 0.3 - 52920;
    } else if (taxableAmount <= 960000) {
      return taxableAmount * 0.35 - 85920;
    } else {
      return taxableAmount * 0.45 - 181920;
    }
  }
}

最后

我最开始尝试写一个 UI 版。但后续感觉,UI 版对于不同语言的用户,会看起来很痛苦。
因此我通过纯 JS 实现,大家可以通过不同的 UI 调用该类,可以在各个框架中使用。
同时也通过 svelte 做了一个简略 UI 版,大家可以直接尝试。

最后,点赞、关注、收藏 ,祝大家多多退税~~