第2-4-8章 规则引擎Drools实战(1)-个人所得税计算器

news2025/1/16 14:52:17

文章目录

    • 9. Drools实战
      • 9.1 个人所得税计算器
        • 9.1.1 名词解释
        • 9.1.2 计算规则
          • 9.1.2.1 新税制主要有哪些变化?
          • 9.1.2.2 资较高人员本次个税较少,可能到年底扣税增加?
          • 9.1.2.3 关于年度汇算清缴
          • 9.1.2.4 个人所得税预扣率表(居民个人工资、薪金所得预扣预缴适用)
          • 9.1.2.5 五险一金缴费比例
        • 9.1.3 实现步骤
          • 9.1.3.1 创建maven工程calculation并配置pom.xml文件
          • 9.1.3.2 创建/resources/application.yml文件
          • 9.1.3.3 编写配置类DroolsConfig
          • 9.1.3.4 编写各种实体类
          • 9.1.3.5 在resources/rules下创建规则文件calculation.drl文件
          • 9.1.3.6 创建RuleServiceImpl
          • 9.1.3.7 创建RuleController
          • 9.1.3.8 创建启动类DroolsApplication

9. Drools实战

全套代码及资料全部完整提供,点此处下载

9.1 个人所得税计算器

本小节我们需要通过Drools规则引擎来根据规则计算个人所得税,最终数据效果如下:

在这里插入图片描述

9.1.1 名词解释

税前月收入:即税前工资,指交纳个人所得税之前的总工资

应纳税所得额:指按照税法规定确定纳税人在一定期间所获得的所有应税收入减除在该纳税期间依法允许减除的各种支出后的余额

税率:是对征税对象的征收比例或征收额度

速算扣除数:指为解决超额累进税率分级计算税额的复杂技术问题,而预先计算出的一个数据,可以简化计算过程

扣税额:是指实际缴纳的税额

税后工资:是指扣完税后实际到手的工资收入

9.1.2 计算规则

要实现个人所得税计算器,需要了解2019个税扣缴变化:

应纳税所得额=(月收入-五险一金-起征点-依法确定的其他扣除-专项附加扣除)*适用税率

9.1.2.1 新税制主要有哪些变化?
  1. 扣缴义务人在支付居民个人工资、薪金所得时,需按照“累计预扣法”核算预扣个人所得税。较之前按月的税率表变化成按年计税,适用个人所得税预扣率表
  2. 首次设立了子女教育、继续教育、大病医疗、住房贷款利息或住房租金、赡养老人六项专项附加扣除。(在税前工资扣除相应额度后核算个税)
9.1.2.2 资较高人员本次个税较少,可能到年底扣税增加?

〔例1〕某职员2015年入职,2019年每月应发工资均为10000元,每月减除费用5000元,“三险一金”等专项扣除为1500元,从1月起享受子女教育专项附加扣除1000元,没有减免收入及减免税额等情况,以前三个月为例,应当按照以下方法计算预扣预缴税额:

1月份:(10000-5000-1500-1000)×3% =75元;

2月份:(10000×2-5000×2-1500×2-1000×2)×3%-75 =75元;

3月份:(10000×3-5000×3-1500×3-1000×3)×3%-75-75 =75元;

进一步计算可知,该纳税人全年累计预扣预缴应纳税所得额为30000元,一直适用3%的税率,因此各月应预扣预缴的税款相同

〔例2〕某职员2015年入职,2019年每月应发工资均为30000元,每月减除费用5000元,“三险一金”等专项扣除为4500元,享受子女教育、赡养老人两项专项附加扣除共计2000元,没有减免收入及减免税额等情况,以前三个月为例,应当按照以下方法计算各月应预扣预缴税额:

1月份:(30000–5000-4500-2000)×3% = 555元;

2月份:(30000×2-5000×2-4500×2-2000×2)×10% -2520 -555 =625元;

3月份:(30000×3-5000×3-4500×3-2000×3)×10% -2520 -555-625 =1850元;

按照上述算法,每一个月应纳个税额:

项目1月2月3月4月5月6月7月8月9月10月11月12月
每月税前工资300003000030000300003000030000300003000030000300003000030000
扣除各项减免额后应对税率3%10%10%10%10%10%10%20%20%20%20%20%
月应预扣预缴个税5556251850185018501850185022503700370037003700

上述计算结果表明,由于2月份累计预扣预缴应纳税所得额为37000元,已适用10%的税率,因此2月份和3月份应预扣预缴有所增高。8月份已适用于20%的税率。根据上述计算结果表明,虽每月工资薪金额和相关扣除额相同,年度内越往后,应纳税所得额越大适用税率越高,则预扣预缴税款可能会越大,会出现类似“12月取得工资10000元预扣预缴的个税税款,比1月份取得工资薪金30000元预扣预缴的个税税款多的”现象。

〔例3〕某职员2022年每月应发工资均为15000元,每月减除费用5000元,养老保险个人缴纳8%,为15000×8%=1200元,失业保险个人缴纳0.5%,为15000×0.5%=75元,医疗保险个人缴纳2%+3元,为15000×2%+3=303元,住房公积金个人缴纳比例12%,为15000×12%=1800元,享受住房租金专项附加扣除1500元,没有减免收入及减免税额等情况,以前三个月的计算为例,应当按照以下方法计算各月应预扣预缴税额:

应纳税所得额=月收入-五险一金-起征点-依法确定的其他扣除-专项附加扣除

1月应纳税所得额=15000–5000-1200-75-303-1800-1500=5122元

1月份:1月应纳税所得额 × 3% = 153.66元;

2月份:1月应纳税所得额 × 2 × 3% -153.66 =153.66元;

3月份:1月应纳税所得额 × 3 × 3% -153.66 - 153.66=153.66元;

按照上述算法,每一个月应纳个税额:

项目1月2月3月4月5月6月7月8月9月10月11月12月
每月税前工资150001500015000150001500015000150001500015000150001500015000
扣除各项减免额后应对税率3%3%3%3%3%3%3%10%10%10%10%10%
月应预扣预缴个税153.66153.66153.66153.66153.66153.66153.66501.98512.2512.2512.2512.2

上述计算结果表明,由于8月份累计预扣预缴应纳税所得额为40976元,已适用10%的税率,因此8月份应预扣预缴有所增高。

9.1.2.3 关于年度汇算清缴

一般来讲,有以下情形之一的,您可以选择在次年3月1日至6月30日内,自行向汇缴地主管税务机关办理汇算清缴申报时进行专项附加扣除,税款多退少补;(1)不愿意通过单位办理扣除,未将相关专项附加扣除信息报送给任职受雇单位的;

(2)在同一纳税年度涉及有两处工资薪金所得或涉及劳务报酬所得的;

(3)有大病医疗支出项目的;

(4)纳税年度内未享受或未足额享受专项附加扣除等情形。

9.1.2.4 个人所得税预扣率表(居民个人工资、薪金所得预扣预缴适用)
级数全年累计预扣预缴应纳税所得额税率(%)速算扣除数
1不超过36,000元的部分30
2超过36,000元至144,000元的部分102520
3超过144,000元至300,000元的部分2016920
4超过300,000元至420,000元的部分2531920
5超过420,000元至660,000元的部分3052920
6超过660,000元至960,000元的部分3585920
7超过960,000元的部分45181920
9.1.2.5 五险一金缴费比例

五险一金缴费比例:养老保险单位21%,个人8%;医疗保险单位9%,个人2%+3元;失业保险单位0.5%,个人0.5%;工伤保险和生育保险由单位缴纳,劳动者不用缴;住房公积金根据企业的实际情况,选择住房公积金缴费比例,下限为5%,最高不超12%。

9.1.3 实现步骤

本实战案例我们基于Spring Boot整合Drools的方式来实现。

目录结构

在这里插入图片描述

9.1.3.1 创建maven工程calculation并配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starters</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>
    <groupId>cn.itcast</groupId>
    <artifactId>calculation</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <!--drools规则引擎-->
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-core</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-templates</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.6.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-spring</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-tx</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                </exclusion>
            </exclusions>
            <version>7.6.0.Final</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
9.1.3.2 创建/resources/application.yml文件
server:
  port: 8080
spring:
  application:
    name: calculation
9.1.3.3 编写配置类DroolsConfig
package com.guohaowei.drools.config;
import cn.hutool.core.date.DatePattern;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;
/**
 * 规则引擎配置类
 */
@Configuration
public class DroolsConfig {
    //指定规则文件存放的目录
    private static final String RULES_PATH = "rules/";
    private final KieServices kieServices = KieServices.Factory.get();
    @Bean
    @ConditionalOnMissingBean
    public KieFileSystem kieFileSystem() throws IOException {
        System.setProperty("drools.dateformat", DatePattern.NORM_DATE_PATTERN);
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        ResourcePatternResolver resourcePatternResolver =
                new PathMatchingResourcePatternResolver();
        Resource[] files =
                resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
        String path;
        for (Resource file : files) {
            path = RULES_PATH + file.getFilename();
            kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
        }
        return kieFileSystem;
    }
    @Bean
    @ConditionalOnMissingBean
    public KieContainer kieContainer() throws IOException {
        KieRepository kieRepository = kieServices.getRepository();
        kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
        kieBuilder.buildAll();
        return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
    }
    @Bean
    @ConditionalOnMissingBean
    public KieBase kieBase() throws IOException {
        return kieContainer().getKieBase();
    }
    @Bean
    @ConditionalOnMissingBean
    public KModuleBeanFactoryPostProcessor kiePostProcessor() {
        return new KModuleBeanFactoryPostProcessor();
    }
}
9.1.3.4 编写各种实体类
  • 编写实体类CalculationDto
package com.guohaowei.drools.domain.dto;

import com.guohaowei.drools.domain.vo.CalculationVo;
import lombok.Data;

import java.math.BigDecimal;
import java.util.List;

/**
 * @author guohaowei
 */
@Data
public class CalculationDto {
    /**
     * 12个月的工资缴税额等信息
     */
    private List<CalculationVo> calculationVoList;
//--------------------------------重复字段用于计算start--------------------------------------------------------
    /**
     * 税前工资
     */
    private BigDecimal wageBeforeTax;
    /**
     * 预扣预缴应纳税所得额
     */
    private BigDecimal taxableIncome;
    /**
     * 累计预扣预缴应纳税所得额
     */
    private BigDecimal taxableIncomeCount;
    /**
     * 月税后工资
     */
    private BigDecimal wageDeductedTax;
//--------------------------------重复字段用于计算end----------------------------------------------------------
    /**
     * 个人所得税起征点
     */
    private BigDecimal threshold;
    /**
     * 养老保险个人缴纳比例,默认8%
     */
    private BigDecimal oldAgeInsuranceRatio;
    /**
     * 失业保险个人缴纳比例,默认0.5%
     */
    private BigDecimal unemploymentInsuranceRatio;
    /**
     * 医疗保险个人缴纳比例,默认2% + 3元
     */
    private BigDecimal medicalInsuranceRatio = BigDecimal.valueOf(0.02);
    /**
     * 医疗保险个人缴纳比例,默认2% + 3元
     */
    private BigDecimal medicalInsuranceAdd = BigDecimal.valueOf(3);
    /**
     * 住房公积金个人缴纳比例,默认12%
     */
    private BigDecimal housingFundRatio;
    /**
     * 住房租金专项附加扣除,默认1500元
     * 其他专项附加扣除同理,此处省略
     */
    private BigDecimal specialAdditionalDeductionRent;

}
  • 编写实体类CalculationVo
package com.guohaowei.drools.domain.vo;

import lombok.Builder;
import lombok.Data;

import java.math.BigDecimal;

/**
 * @author guohaowei
 */
@Data
@Builder
public class CalculationVo {
    /**
     * 月税前工资
     */
    private BigDecimal wageBeforeTax;
    /**
     * 月预扣预缴应纳税所得额
     */
    private BigDecimal taxableIncome;
    /**
     * 月税率
     */
    private BigDecimal taxRate;
    /**
     * 月速算扣除数
     */
    private BigDecimal quickDeduction;
    /**
     * 月扣税额
     */
    private BigDecimal taxRebate;
    /**
     * 月税后工资
     */
    private BigDecimal wageDeductedTax;
    /**
     * 月份
     */
    private Integer month;
}
  • 编写枚举类WithholdingTaxRateEnum
package com.guohaowei.drools.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.math.BigDecimal;

/**
 * @Author: 郭浩伟 qq:912161367
 * @Date: 2022/11/17 0017 7:18
 * @Description: 个人所得税预扣率表(居民个人工资、薪金所得预扣预缴适用)
 */
@AllArgsConstructor
@Getter
public enum WithholdingTaxRateEnum {
    /**
     * 级数
     */
    one(36_000, "0.03", 0),
    two(144_000, "0.10", 2520),
    three(300_000, "0.20", 16920),
    four(420_000, "0.25", 31920),
    five(660_000, "0.30", 52920),
    six(960_000, "0.35", 85920),
    seven(960_000, "0.45", 181920),
    ;

    /**
     * 全年累计预扣预缴应纳税所得额
     */
    private Integer taxableIncome;
    /**
     * 税率,如0.03
     */
    private String taxRate;
    /**
     * 速算扣除数
     */
    private Integer quickDeduction;

    /**
     * 根据【应纳税所得额】得到含对应的【税率】和【速算扣除数】的枚举值
     *
     * @param actualTaxableIncome
     * @return
     */
    public static WithholdingTaxRateEnum getInfoByIncome(BigDecimal actualTaxableIncome) {
        if(null == actualTaxableIncome){
            return null;
        }
        for (WithholdingTaxRateEnum value : WithholdingTaxRateEnum.values()) {
            if(actualTaxableIncome.compareTo(BigDecimal.valueOf(value.getTaxableIncome())) <= 0){
                return value;
            }
        }
        return seven;
    }
}
  • 编写实体类CalculationReq
package com.guohaowei.drools.domain.req;


import lombok.Data;

import java.math.BigDecimal;

/**
 * @Author: 郭浩伟 qq:912161367
 * @Date: 2022/11/16 0016 23:31
 * @Description:
 */
@Data
public class CalculationReq {
    /**
     * 税前工资
     */
    private BigDecimal wageBeforeTax;
    /**
     * 个人所得税起征点,默认5000元
     */
    private BigDecimal threshold = BigDecimal.valueOf(5000);
    /**
     * 养老保险个人缴纳比例,默认8%
     */
    private BigDecimal oldAgeInsuranceRatio = BigDecimal.valueOf(0.08);
    /**
     * 失业保险个人缴纳比例,默认0.5%
     */
    private BigDecimal unemploymentInsuranceRatio = BigDecimal.valueOf(0.005);
    /**
     * 医疗保险个人缴纳比例,默认2% + 3元
     */
    private BigDecimal medicalInsuranceRatio = BigDecimal.valueOf(0.02);
    /**
     * 医疗保险个人缴纳比例,默认2% + 3元
     */
    private BigDecimal medicalInsuranceAdd = BigDecimal.valueOf(3);
    /**
     * 住房公积金个人缴纳比例,默认12%
     */
    private BigDecimal housingFundRatio = BigDecimal.valueOf(0.12);
    /**
     * 住房租金专项附加扣除,默认1500元
     * 其他专项附加扣除同理,此处省略
     */
    private BigDecimal specialAdditionalDeductionRent = BigDecimal.valueOf(1500);

}
9.1.3.5 在resources/rules下创建规则文件calculation.drl文件
//当前规则文件用于计算个人所得税
package calculation
import java.math.BigDecimal
import com.guohaowei.drools.domain.dto.CalculationDto
import com.guohaowei.drools.enums.WithholdingTaxRateEnum
import java.util.ArrayList
import com.guohaowei.drools.domain.vo.CalculationVo
import java.util.List
global com.guohaowei.drools.domain.dto.CalculationDto calculationGlobalDto
/**
    当前规则文件中的规则主要分为三类
    1、计算应纳税所得额有1个规则
    2、设置税率、速算扣除数有7个规则
    3、计算税后工资有1个规则
**/

//计算应纳税所得额
rule "计算应纳税所得额-减去个税起征点"
    salience 100
    date-effective "2019-01-01"
    no-loop true
    when
    then
        //税前工资
        BigDecimal wageBeforeTax = calculationGlobalDto.getWageBeforeTax();
        BigDecimal taxableIncome = wageBeforeTax.subtract(calculationGlobalDto.getThreshold());

        calculationGlobalDto.setWageBeforeTax(wageBeforeTax);
        calculationGlobalDto.setWageDeductedTax(wageBeforeTax);
        calculationGlobalDto.setTaxableIncome(BigDecimal.ZERO);
        if(taxableIncome.compareTo(BigDecimal.valueOf(0)) > 0){
            calculationGlobalDto.setTaxableIncome(taxableIncome);
        }

end

rule "计算应纳税所得额-减去养老保险个人缴纳金额"
    salience 99
    date-effective "2019-01-01"
    no-loop true
    when
    then
        //养老保险个人缴纳额
        BigDecimal oldAgeInsurance = calculationGlobalDto.getWageBeforeTax().multiply(calculationGlobalDto.getOldAgeInsuranceRatio());
        //预扣预缴应纳税所得额
        BigDecimal taxableIncome = calculationGlobalDto.getTaxableIncome();
        //应纳税所得额如果小于0即不需要缴税也就不需要计算了
        if(taxableIncome.compareTo(BigDecimal.valueOf(0)) > 0){
            taxableIncome = taxableIncome.subtract(oldAgeInsurance);
        calculationGlobalDto.setTaxableIncome(taxableIncome);
        }
        //税后工资
        calculationGlobalDto.setWageDeductedTax(calculationGlobalDto.getWageBeforeTax().subtract(oldAgeInsurance));
end

rule "计算应纳税所得额-减去失业保险个人缴纳金额"
    salience 98
    date-effective "2019-01-01"
    no-loop true
    when
    then
        //失业保险个人缴纳额
        BigDecimal unemploymentInsurance = calculationGlobalDto.getWageBeforeTax().multiply(calculationGlobalDto.getUnemploymentInsuranceRatio());
        //应纳税所得额如果小于0即不需要缴税也就不需要计算了
        if(calculationGlobalDto.getTaxableIncome().compareTo(BigDecimal.valueOf(0)) > 0){
            BigDecimal taxableIncome = calculationGlobalDto.getTaxableIncome().subtract(unemploymentInsurance);
            calculationGlobalDto.setTaxableIncome(taxableIncome);
        }
        //税后工资
        calculationGlobalDto.setWageDeductedTax(calculationGlobalDto.getWageDeductedTax().subtract(unemploymentInsurance));
end

rule "计算应纳税所得额-减去医疗保险个人缴纳金额"
    salience 97
    date-effective "2019-01-01"
    no-loop true
    when
    then
        //医疗保险个人缴纳额
        BigDecimal medicalInsurance = calculationGlobalDto.getWageBeforeTax().multiply(calculationGlobalDto.getMedicalInsuranceRatio()).add(calculationGlobalDto.getMedicalInsuranceAdd());
        //应纳税所得额如果小于0即不需要缴税也就不需要计算了
        if(calculationGlobalDto.getTaxableIncome().compareTo(BigDecimal.valueOf(0)) > 0){
            BigDecimal taxableIncome = calculationGlobalDto.getTaxableIncome().subtract(medicalInsurance);
            calculationGlobalDto.setTaxableIncome(taxableIncome);
        }
        //税后工资
        calculationGlobalDto.setWageDeductedTax(calculationGlobalDto.getWageDeductedTax().subtract(medicalInsurance));
end

rule "计算应纳税所得额-减去住房公积金个人缴纳金额"
    salience 96
    date-effective "2019-01-01"
    no-loop true
    when
    then
        //住房公积金个人缴纳额
        BigDecimal housingFund = calculationGlobalDto.getWageBeforeTax().multiply(calculationGlobalDto.getHousingFundRatio());
        //应纳税所得额如果小于0即不需要缴税也就不需要计算了
        if(calculationGlobalDto.getTaxableIncome().compareTo(BigDecimal.valueOf(0)) > 0){
            BigDecimal taxableIncome = calculationGlobalDto.getTaxableIncome().subtract(housingFund);
            calculationGlobalDto.setTaxableIncome(taxableIncome);
        }
        //税后工资
        calculationGlobalDto.setWageDeductedTax(calculationGlobalDto.getWageDeductedTax().subtract(housingFund));
end

rule "计算应纳税所得额-减去住房租金专项附加扣除金额"
    salience 95
    date-effective "2019-01-01"
    no-loop true
    when
    then
    //应纳税所得额如果小于0即不需要缴税也就不需要计算了
     if(calculationGlobalDto.getTaxableIncome().compareTo(BigDecimal.valueOf(0)) > 0){
        BigDecimal taxableIncome = calculationGlobalDto.getTaxableIncome().subtract(calculationGlobalDto.getSpecialAdditionalDeductionRent());
        calculationGlobalDto.setTaxableIncome(taxableIncome);
     }
end

rule "计算出最终的统计结果"
    salience 94
    date-effective "2019-01-01"
    no-loop true
    when
    then
        List<CalculationVo> calculationVoList = new ArrayList<>();
        BigDecimal taxRebateCount = BigDecimal.ZERO;
        //当月扣税额=应纳税所得额x月份数x税率-速算扣除数-累计扣税额
        for(int i = 1; i <= 12 ; i++) {
          //累计应纳税所得额
          BigDecimal taxableIncomeCount = calculationGlobalDto.getTaxableIncome().multiply(BigDecimal.valueOf(i));
          WithholdingTaxRateEnum withholdingTaxRateEnum = WithholdingTaxRateEnum.getInfoByIncome(taxableIncomeCount);
          //月税率
          BigDecimal taxRate = new BigDecimal(withholdingTaxRateEnum.getTaxRate());
          //月速算扣除数
          BigDecimal quickDeduction = BigDecimal.valueOf(withholdingTaxRateEnum.getQuickDeduction());
          //月扣税额
          BigDecimal taxRebate =taxableIncomeCount.multiply(taxRate).subtract(quickDeduction).subtract(taxRebateCount);
          //累计扣税额
          taxRebateCount = taxRebateCount.add(taxRebate);
          //组装vo
          CalculationVo calculationVo = CalculationVo.builder().wageBeforeTax(calculationGlobalDto.getWageBeforeTax()).taxableIncome(calculationGlobalDto.getTaxableIncome()).
          taxRate(taxRate).quickDeduction(quickDeduction).taxRebate(taxRebate).wageDeductedTax(calculationGlobalDto.getWageDeductedTax().subtract(taxRebate)).month(i).build();
          calculationVoList.add(calculationVo);
        }
        calculationGlobalDto.setCalculationVoList(calculationVoList);
end

9.1.3.6 创建RuleServiceImpl
package com.guohaowei.drools.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.guohaowei.drools.domain.dto.CalculationDto;
import com.guohaowei.drools.domain.req.CalculationReq;
import com.guohaowei.drools.domain.vo.CalculationVo;
import com.guohaowei.drools.service.RuleService;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
/**
 * @Author: 郭浩伟 qq:912161367
 * @Date: 2022/11/18 0018 19:41
 * @Description:
 */
@Service
public class RuleServiceImpl implements RuleService {
    @Autowired
    private KieBase kieBase;

    /**
     * 调用Drools规则引擎实现个人所得税计算
     *
     * @param req
     * @return
     */
    @Override
    public List<CalculationVo> calculate(CalculationReq req) {
        KieSession session = kieBase.newKieSession();
        CalculationDto calculationDto = BeanUtil.copyProperties(req, CalculationDto.class);
        //初始化税后工资=税前工资
        calculationDto.setWageDeductedTax(calculationDto.getWageBeforeTax());
        //设置全局变量,名称和类型必须和规则文件中定义的全局变量名称对应
        session.setGlobal("calculationGlobalDto",calculationDto);
        session.fireAllRules();
        session.dispose();
        return calculationDto.getCalculationVoList();
    }
}

9.1.3.7 创建RuleController
package com.guohaowei.drools.controller;

import com.guohaowei.drools.domain.req.CalculationReq;
import com.guohaowei.drools.domain.vo.CalculationVo;
import com.guohaowei.drools.service.impl.RuleServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/rule")
public class RuleController {
    @Autowired
    private RuleServiceImpl ruleService;

    @RequestMapping("/calculate")
    public List<CalculationVo> calculate(@RequestBody CalculationReq req){
        return ruleService.calculate(req);
    }
}

9.1.3.8 创建启动类DroolsApplication
package com.guohaowei.drools;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DroolsApplication {
    public static void main(String[] args) {
        SpringApplication.run(DroolsApplication.class);
    }
}

全套代码及资料全部完整提供,点此处下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/44834.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

科教导刊杂志科教导刊杂志社科教导刊编辑部2022年第27期目录

前沿视角《科教导刊》投稿&#xff1a;cn7kantougao163.com 新时代研究生教育质量评价指标体系的框架构建 李军伟;赵永克;杨丹; 1-3 基于现代学徒制的“多主体、双标准、五维度”人才培养质量评价体系构建 汪帆;刘严; 4-6 高教论坛 新工科背景下地方性院校第二课堂…

【云原生】Docker容器服务更新与发现之consul

内容预知 1.consul的相关知识 1.1 什么是注册与发现 1.2 什么是consul 1.3 zookeeper和consul的区别 2. consul 部署 2.1 部署consul服务器 2.2 registrator服务器 3.consul-template 的引入 3.1 consul-template的作用 3.2 consul-template的具体部署运用 &…

微信开发者工具C盘占用大的问题

将User Data 下的文件迁移到其他盘&#xff0c;比如 D盘&#xff0c;E盘&#xff0c;F盘 步骤如下&#xff1a; 1.找到微信开发者工具C盘所在的缓存目录&#xff0c;一般为 C:\Users\ 你的用户名\AppData\Local\微信开发者工具\User Data 将里面的内容全部剪切到其它盘符&…

从鹅厂实例出发!分析Go Channel底层原理

本文是基于Go1.18.1源码的学习笔记。Channel的底层源码从Go1.14到现在的Go1.19之间几乎没有变化&#xff0c;这也是Go最早引入的组件之一&#xff0c;体现了Go并发思想&#xff1a;Do not communicate by sharing memory; instead, share memory by communicating.不要通过共享…

Playwright 简明入门教程:录制自动化测试用例,结合 Docker 使用

本篇文章聊聊如何使用 Playwright 进行测试用例的录制生成&#xff0c;以及如何在Docker 容器运行测试用例&#xff0c;或许是网上最简单的入门教程。 写在前面 Playwright 是微软出品的 Web 自动化测试工具和框架&#xff0c;和 Google Puppeteer 有着千丝万缕的关系。前一阵…

[附源码]计算机毕业设计springboot儿童早教课程管理系统论文2022

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

如何治理 Electron 版本淘宝直播应用崩溃?

经过几个月的努力&#xff0c;基于Electron框架开发的新版淘宝直播推流软件终于上线了。随之而来的就是线上用户反馈的各种问题&#xff0c;其中最影响用户体验的当属应用崩溃问题了。当应用程序出现未 catch 的异常时就会发生崩溃&#xff0c;本文介绍了客户端应用崩溃的处理流…

javaSE - Arrays - 数组的定义与使用

一、数组基本用法 1.1、什么是数组 数组本质上就是让我们能 “批量” 创建相同类型的变量 也可以说是存储一组相同数据类型的数据的集合 如: 如果需要表示两个数据, 那么直接创建两个变量即可 int a; int b 如果需要表示五个数据, 那么可以创建五个变量 int a1; int a2; int …

uni-app入门:自定义组件实现父子组件参数传递

1.属性绑定:父组件传递参数到子组件 2.事件绑定:子组件传递参数到父组件 3.获取组件对象实例:父组件获取子组件实例对象进行参数传递 1.属性绑定:父组件传递参数到子组件首先交代一下基本的项目信息:主页面为index.wxml,创建test子组件,文件目录:component/test/test…

惠柏新材创业板IPO过会:上半年营收9.3亿 拟募资3.4亿

雷递网 雷建平 11月28日惠柏新材料科技&#xff08;上海&#xff09;股份有限公司&#xff08;简称&#xff1a;“惠柏新材”&#xff09;日前IPO过会&#xff0c;准备在深交所创业板上市。惠柏新材计划募资3.42亿元&#xff0c;其中&#xff0c;1.8亿元用于上海帝福3.7万吨纤维…

xss-labs/level9

这一关界面感觉跟上一关很像 所以我们注入上一关的为编码的答案 javascript:alert(xss) 没能弹窗 查看源代码 他说我输入的链接不合法 我压根没有输入链接 我觉得后台应该是做了一个条件的判断 应该是要有链接才会在第二处输出点回显我们的输入 根据上面的猜测 我们构造如下…

网络的根基

hi 大家好&#xff0c;上个周末带小伙伴&#xff0c;一起复习了一遍网络协议&#xff0c;对网络协议的核心知识进行梳理&#xff0c;希望大家早日掌握这些核心知识&#xff0c;打造自己坚实的基础&#xff0c;为自己目标慢慢积累&#xff0c;等到自己春天的到来。详细点击查看…

设计模式学习笔记

文章目录23种设计模式学习笔记1.创建型模式1 单例模式2 工厂模式3 抽象工厂模式4 建造者模式5 原型模式2.结构型模式6 代理模式7 适配器模式8 桥接模式9 装饰模式10 外观模式11 组合模式12 享元模式3.行为型模式13 策略模式14 观察者模式15 责任链模式16 模板模式17 状态模式18…

Maven程序 tomcat插件安装与web工程启动

第一步&#xff1a;在mvnrepository库中找到tomcat插件 1.打开mvnrepository官网&#xff0c;搜索“tomcat maven”向下滑动找到“org.apache.tomcat.maven ”点进去 2.在这里点第一个“Apache Tomcat Maven Plugin :: Tomcat 7.x” 3.在这里选择2.1版本相对来说比较稳定 4.复…

jsp393学生宿舍管理系统mysql

两个权限 管理员和 学生 1. 学生信息管理 添加学生信息&#xff08;学生号&#xff0c;姓名 院系 班级入学日期 &#xff09;修改学生信息 学生退宿舍&#xff08;可以删除指定的学生也可以成批删除&#xff09; 2. 宿舍信息管理 宿舍的基本信息&#xff08;公寓数 宿舍…

DSP-数字滤波器的结构

目录 基本结构块: 例&#xff1a; 一些特殊结构&#xff1a; 无延时回路问题&#xff1a; 规范和非规范结构&#xff1a; 等效结构&#xff1a; FIR滤波器的基本结构 &#xff1a; 直接型&#xff1a; 级联型&#xff1a; 多相型: 线性相位FIR结构: 基本IIR滤波器结…

模拟可执行的四旋翼模型——在未知环境下运动规划应用研究(Matlab代码实现)

1 概述 无人机现在利用最佳搜索策略&#xff0c;使用PRISM模型检查器生成&#xff0c;以寻找目标。本文设计并编写了一种对抗性模式搜索算法来比较性能。 四旋翼无人机由于具有可悬停,可垂直起降,在设计速度范围内向任意方向飞行的运动特点,以及结构简单,构造容易,成本低廉等…

解析异常SAXParseExceptionis如何处理

1.问题背景 今天一位同事找我寻求帮助&#xff0c;售后向他反馈的问题不知道如何排查&#xff0c;他尝试分析服务器端日志文件&#xff0c; 但是日志文件中并没有报错信息&#xff0c;查询源码时候发现&#xff0c;报错信息被try...catch处理 2.排查过程 顺便提一句&#xff…

微服务框架 SpringCloud微服务架构 4 Ribbon 4.3 饥饿加载

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构4 Ribbon4.3 饥饿加载4.3.1 饥饿加载4.3.2 总结4 Ribbon 4.3 饥饿加载 4…

实验四-----数据库

一、实验目的 1.理解SQL 的视图以及与基本表的区别&#xff1b; 2.掌握SQL 视图的定义、查询、更新&#xff1b; 二、实验环境 1&#xff0e;实验室名称&#xff1a;软件实验室 2&#xff0e;主要仪器设备&#xff1a;PC机、SQL Server2008环境 三、实验内容 1.对学生数据…