前言

最近构建公司财务计税零碎,因为我国税种较多,且不同税种的金额梯度不同,计算公式也不,并且因为业务须要,时而须要正向计算税额(税前推税后),时而须要反向计算税额(税后推税前).构建架构时,想基于一个接口,且易于扩大。遂有了应用工厂+策略模式易于扩大的想法。

策略应用前剖析

(公司平安起因,我就不写具体场景了,这里以场景一,场景二,场景三...来代替)
目前须要计税的有场景一/场景二/场景三。而每种场景又分为正向计算/逆向计算两种计算形式,故咱们须要应用的策略维度有:

1.场景一 + 正向计算2.场景一 + 逆向计算3.场景二 + 正向计算4.场景二 + 逆向计算5.场景三 + 正向计算6.场景四 + 逆向计算

咱们能够在Spring容器启动的时候,将这几种case加载spring的时候就存在某个中央,这样咱们须要哪种场景,传递具体code,取出咱们须要的strategy就好了。那么很显著,咱们能够在工厂外面放一个hashmap用来存储具体的strategy,如下:

/** * @author LiuLiang (iamcrawler@sina.com) * @since 2020-11-16 11:52 */ @Componentpublic class TaxCalculateStrategyFactory {    private static Map<String, TaxCalculateStrategy> strategyMap = new ConcurrentHashMap(); /** * 获取实现策略 * * @param model * @return */ public static TaxCalculateStrategy getInvokeStrategyByModel(String model) {        return strategyMap.get(model); }    public static void register(String str, TaxCalculateStrategy iTaxStrategyService) {        if (StringUtils.isEmpty(str) || null == iTaxStrategyService) {            return; }        strategyMap.put(str, iTaxStrategyService); }}

有了这个工厂,咱们须要在spring容器启动的时候,就把具体strategy放到map外面,当然这个时候形式有很多种,比方在结构的时候放进去等等,当然我集体认为,此动作不应该和具体的bean有太大的耦合关系,故我应用的形式是实现spring的 InitializingBean ,并 实现本人的策略父类如下:

策略父类:

public interface TaxCalculateStrategy {    /** * @param monthlySumIncome 月总收入 * @param monthlySumTax 月总(已)缴纳税额 * @param currentIncome 以后笔支出 * @return */ Long calculate(Long monthlySumIncome, Long monthlySumTax, Long currentIncome);}

策略具体实现类

/** * 劳务税正算逻辑 * * @author LiuLiang * @since 2020-11-16 11:28 */@Servicepublic class LaborTaxForwardCalculateStrategy implements TaxCalculateStrategy, InitializingBean {    @Override public Long calculate(Long monthlySumIncome, Long monthlySumTax, Long currentIncome) {  //税前总金额 Long preTaxIncome = monthlySumIncome + monthlySumTax + currentIncome; //税后总金额 Long afterTaxIncome = getAfterTaxIncome(preTaxIncome); //总税额 Long totalTax = preTaxIncome - afterTaxIncome; //本次税额 Long currentTax = totalTax - monthlySumTax; return currentTax; }    /** * 劳务税 正向计算公式 * 应征税所得额 = 劳务报酬(少于4000元) - 800元 * <p> * 应征税所得额 = 劳务报酬(超过4000元) × (1 - 20%) * <p> * 应纳税额 = 应征税所得额 × 实用税率 - 速算扣除数 * <p> * 阐明: * <p> * 1、劳务报酬所得在800元以下的,不必缴纳个人所得税; * <p> * 2、劳务报酬所得大于800元且没有超过4000元,可减除800元的扣除费用; * <p> * 3、劳务报酬所得超过4000元的,可减除劳务报酬支出20%的扣除费用; * <p> * 个税计算器税率表 * 级数  应征税所得额 税率(%)  速算扣除数 * 1   不超过20,000元 20%    0 * 2   超过20,000元至50,000元的局部   30%    2,000 * 3   超过50,000元的局部   40%    7,000 * * @param preTaxIncome 税前金额 单位:分 * @return */ public Long getAfterTaxIncome(Long preTaxIncome) {        Long afterTaxIncome = preTaxIncome; //应征税所得额 BigDecimal taxableIncome = BigDecimal.ZERO; if (!(preTaxIncome > TaxCenterConstant.RMB_4000.longValue())) {            taxableIncome = BigDecimal.valueOf(preTaxIncome).subtract(TaxCenterConstant.RMB_800); } else {            taxableIncome = BigDecimal.valueOf(preTaxIncome).multiply(TaxCenterConstant.TAXABLE_INCOME_RATE_8); }        if (taxableIncome.compareTo(BigDecimal.ZERO) < 0) {            return afterTaxIncome; } else if (taxableIncome.compareTo(TaxCenterConstant.RMB_20000) < 0) {            return preTaxIncome - taxableIncome.multiply(TaxCenterConstant.WITHHOLDING_RATE_20).longValue(); } else if (taxableIncome.compareTo(TaxCenterConstant.RMB_50000) < 0 && taxableIncome.compareTo(TaxCenterConstant.RMB_20000) > 0) {            return preTaxIncome - taxableIncome.multiply(TaxCenterConstant.WITHHOLDING_RATE_30).subtract(TaxCenterConstant.RMB_2000).longValue(); } else if (taxableIncome.compareTo(TaxCenterConstant.RMB_50000) > 0) {            return preTaxIncome - taxableIncome.multiply(TaxCenterConstant.WITHHOLDING_RATE_40).subtract(TaxCenterConstant.RMB_7000).longValue(); }        return afterTaxIncome; }    @Override public void afterPropertiesSet() throws Exception {        TaxCalculateStrategyFactory.register("LABOR-FORWARD", this); }

能够看到afterPropertiesSet 办法以及把具体的code register 到动态的hashmap外面去了,具体的实现,在从新父类的calculate() 办法外面。同理其余的几个策略,就不贴具体代码了

怎么应用?

public BigDecimal taxCalculate(Long currentIncomeAmount, Long monthlyIncome, Long monthlyTax) {    //依照既定策略计算税额 TaxCalculateStrategy strategy = TaxCalculateStrategyFactory.getInvokeStrategyByModel(            SceneCodeIncomeEnum.SOW_GRASS.getTaxType() + "-" + SceneCodeIncomeEnum.SOW_GRASS.getModel()); Long currentTax = strategy.calculate(monthlyIncome, monthlyTax, currentIncomeAmount); return BigDecimal.valueOf(currentTax);}

能够看到,咱们拿到具体的策略后,调用calculate办法就好了.策略会帮忙咱们走具体逻辑.