if (CollectionUtils.isNotEmpty(serviceFeeDos)) { var transportAmount = transportSettleDetailDO.getTransportAmount(); var ownCarServiceFee = new BigDecimal(0); var ownCarServiceFeeTaxEncluded = new BigDecimal(0); for (TmsTransportSupplierPlatformServiceFeeDo serviceFeeDo : serviceFeeDos) { // 堆代码 duidaima.com //获取当前算法配置运算符 var operator = serviceFeeDo.getOperator(); AlgorithmEnum algorithmEnum = AlgorithmEnum.tEnum(operator); switch (algorithmEnum) { case ADD: ownCarServiceFee = ownCarServiceFee.add(transportAmount.add(serviceFeeDo.getNumerical())); break; case SUBTRACT: ownCarServiceFee = ownCarServiceFee.add(transportAmount.subtract(serviceFeeDo.getNumerical())); break; case MULTIPLY: ownCarServiceFee = ownCarServiceFee.add(transportAmount.multiply(serviceFeeDo.getNumerical())); break; case DIVIDE: ownCarServiceFee = ownCarServiceFee.add(transportAmount.divide(serviceFeeDo.getNumerical(), 4, RoundingMode.HALF_UP)); break; } ownCarServiceFeeTaxEncluded = ownCarServiceFeeTaxEncluded.add(ownCarServiceFee.divide(new BigDecimal(1).add(new BigDecimal(tmsTransportSupplierRateItemDO.getTax()).divide(new BigDecimal(100))), 4, RoundingMode.HALF_UP)); var operationalLogic = serviceFeeDo.getOperationalLogic(); //获取当前算法配置运算关系 AlgorithmEnum operationalLogicEnum = AlgorithmEnum.tEnum(operationalLogic); switch (operationalLogicEnum) { case ADD: transportAmount = transportAmount.add(transportAmount.add(ownCarServiceFee)); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; case SUBTRACT: transportAmount = transportAmount.add(transportAmount.subtract(ownCarServiceFee)); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; case MULTIPLY: transportAmount = transportAmount.add(transportAmount.multiply(ownCarServiceFee)); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; case DIVIDE: AssertUtil.assertTrue(ownCarServiceFee.compareTo(BigDecimal.ZERO) <= 0, ErrorCodeEnum.ZY100010004); transportAmount = transportAmount.add(transportAmount.divide(ownCarServiceFee)); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; } } }初版的问题在于算法错误,当配置多个算法配置时,取服务费F的值应为本次的值,如上图则为每次的叠加值,其免税税率也应为本次的值计算税率
if(CollectionUtils.isNotEmpty(serviceFeeDos)){ var transportAmount = transportSettleDetailDO.getTotalAmount(); var totalAmountTaxEncluded = transportSettleDetailDO.getTotalAmountTaxEncluded(); var ownCarServiceFee = new BigDecimal(0); var ownCarServiceFeeTaxEncluded = new BigDecimal(0); for (TmsTransportSupplierPlatformServiceFeeDo serviceFeeDo : serviceFeeDos) { Integer operator = serviceFeeDo.getOperator(); AlgorithmEnum algorithmEnum = AlgorithmEnum.tEnum(operator); switch (algorithmEnum) { case ADD: ownCarServiceFee = transportAmount.add(serviceFeeDo.getNumerical()); break; case SUBTRACT: ownCarServiceFee = transportAmount.subtract(serviceFeeDo.getNumerical()); break; case MULTIPLY: ownCarServiceFee = transportAmount.multiply(serviceFeeDo.getNumerical()); break; case DIVIDE: AssertUtil.assertTrue(serviceFeeDo.getNumerical().compareTo(BigDecimal.ZERO) <= 0, ErrorCodeEnum.ZY100010004); ownCarServiceFee = transportAmount.divide(serviceFeeDo.getNumerical(),4, RoundingMode.HALF_UP); break; } ownCarServiceFeeTaxEncluded = ownCarServiceFee.divide(new BigDecimal(1).add(new BigDecimal(tmsTransportSupplierRateItemDO.getTax()).divide(new BigDecimal(100))), 4, RoundingMode.HALF_UP); Integer operationalLogic = serviceFeeDo.getOperationalLogic(); AlgorithmEnum operationalLogicEnum = AlgorithmEnum.tEnum(operationalLogic); switch (operationalLogicEnum) { case ADD: transportAmount = transportAmount.add(ownCarServiceFee); totalAmountTaxEncluded = totalAmountTaxEncluded.add(ownCarServiceFeeTaxEncluded); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0 , ErrorCodeEnum.ZY100010004); break; case SUBTRACT: transportAmount = transportAmount.subtract(ownCarServiceFee); totalAmountTaxEncluded = totalAmountTaxEncluded.subtract(ownCarServiceFeeTaxEncluded); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; case MULTIPLY: transportAmount = transportAmount.multiply(ownCarServiceFee); totalAmountTaxEncluded = totalAmountTaxEncluded.multiply(ownCarServiceFeeTaxEncluded); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; case DIVIDE: AssertUtil.assertTrue(ownCarServiceFee.compareTo(BigDecimal.ZERO) <= 0 || ownCarServiceFeeTaxEncluded.compareTo(BigDecimal.ZERO) <= 0, ErrorCodeEnum.ZY100010004); transportAmount = transportAmount.divide(ownCarServiceFee,4, RoundingMode.HALF_UP); totalAmountTaxEncluded = totalAmountTaxEncluded.divide(ownCarServiceFeeTaxEncluded,4, RoundingMode.HALF_UP); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; } }如上逻辑已经可以适配,但此时逻辑变更图片,产品发现此算法配置无法直接配置某次运费,应适配某次费用为指定费用小改动如下
if (PlatFormServiceFeeTypeEnum.平台服务费.desc().equals(serviceFeeDo.getFeeType())) { ownCarServiceFee = serviceFeeDo.getNumerical(); }但还没有进行测试,逻辑再次变更,需要兼容税率为小数,再次改多个字段逻辑后提交,但是此时的如上图算法配置,代码直接取值第二个服务费为100,最终的服务费计算错误,其余值计算正确,第二天又又讨论此计算逻辑错误图片图片图片跟产品测试吵了一架后不欢而散,静下心来开始思考如何提取公共逻辑
如果第一次为任何场景,则取值的计算逻辑是没问题的,但是当配置多个算法,计算第i+1个的时候,其计算逻辑的通配逻辑应为(本次费用 (运算符关系(+或-)) 上一次的运费)来计算,但每次的单独费用还是取单次的计算逻辑,最终费用的税率再次进行计算;说来容易,因为最终的解决方案出来了,但是思考的过程其实吵完了后也很难纠正,因为这个逻辑是在出现第二个场景后才出现的不适配,思考找到通用的代码逻辑才能好写。
最终代码如下:
if (CollectionUtils.isNotEmpty(serviceFeeDos)) { var transportAmount = transportSettleDetailDO.getTotalAmount(); var totalAmountTaxEncluded = transportSettleDetailDO.getTotalAmountTaxEncluded(); var ownCarServiceFee = new BigDecimal(0); var ownCarServiceFeeTaxEncluded = new BigDecimal(0); var tempOwnCarServiceFee = new BigDecimal(0); var tempOwnCarServiceFeeTaxEncluded = new BigDecimal(0); for (TmsTransportSupplierPlatformServiceFeeDo serviceFeeDo : serviceFeeDos) { var operator = serviceFeeDo.getOperator(); if(serviceFeeDo.getTransportSort() > 1) { tempOwnCarServiceFee = ownCarServiceFee; } AlgorithmEnum algorithmEnum = AlgorithmEnum.tEnum(operator); if (PlatFormServiceFeeTypeEnum.单趟运费.desc().equals(serviceFeeDo.getFeeType())) { switch (algorithmEnum) { case ADD: ownCarServiceFee = transportAmount.add(serviceFeeDo.getNumerical()); break; case SUBTRACT: ownCarServiceFee = transportAmount.subtract(serviceFeeDo.getNumerical()); break; case MULTIPLY: ownCarServiceFee = transportAmount.multiply(serviceFeeDo.getNumerical()); break; case DIVIDE: AssertUtil.assertTrue(serviceFeeDo.getNumerical().compareTo(BigDecimal.ZERO) <= 0, ErrorCodeEnum.ZY100010004); ownCarServiceFee = transportAmount.divide(serviceFeeDo.getNumerical(), 4, RoundingMode.HALF_UP); break; } } var operationalLogic = serviceFeeDo.getOperationalLogic(); AlgorithmEnum operationalLogicEnum = AlgorithmEnum.tEnum(operationalLogic); if (PlatFormServiceFeeTypeEnum.平台服务费.desc().equals(serviceFeeDo.getFeeType())) { ownCarServiceFee = serviceFeeDo.getNumerical(); } ownCarServiceFeeTaxEncluded = ownCarServiceFee.divide(new BigDecimal(1).add(tmsTransportSupplierRateItemDO.getTax().divide(new BigDecimal(100))), 4, RoundingMode.HALF_UP); switch (operationalLogicEnum) { case ADD: transportAmount = transportAmount.add(ownCarServiceFee); totalAmountTaxEncluded = totalAmountTaxEncluded.add(ownCarServiceFeeTaxEncluded); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; case SUBTRACT: transportAmount = transportAmount.subtract(ownCarServiceFee); totalAmountTaxEncluded = totalAmountTaxEncluded.subtract(ownCarServiceFeeTaxEncluded); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; case MULTIPLY: transportAmount = transportAmount.multiply(ownCarServiceFee); totalAmountTaxEncluded = totalAmountTaxEncluded.multiply(ownCarServiceFeeTaxEncluded); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; case DIVIDE: AssertUtil.assertTrue(ownCarServiceFee.compareTo(BigDecimal.ZERO) <= 0 || ownCarServiceFeeTaxEncluded.compareTo(BigDecimal.ZERO) <= 0, ErrorCodeEnum.ZY100010004); transportAmount = transportAmount.divide(ownCarServiceFee, 4, RoundingMode.HALF_UP); totalAmountTaxEncluded = totalAmountTaxEncluded.divide(ownCarServiceFeeTaxEncluded, 4, RoundingMode.HALF_UP); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; } if(serviceFeeDo.getTransportSort() > 1){ switch (operationalLogicEnum) { case ADD: ownCarServiceFee = tempOwnCarServiceFee.add(ownCarServiceFee); break; case SUBTRACT: ownCarServiceFee = tempOwnCarServiceFee.subtract(ownCarServiceFee); break; case MULTIPLY: ownCarServiceFee = tempOwnCarServiceFee.multiply(ownCarServiceFee); break; case DIVIDE: AssertUtil.assertTrue(ownCarServiceFee.compareTo(BigDecimal.ZERO) <= 0 || ownCarServiceFeeTaxEncluded.compareTo(BigDecimal.ZERO) <= 0, ErrorCodeEnum.ZY100010004); ownCarServiceFee = tempOwnCarServiceFee.divide(ownCarServiceFee, 4, RoundingMode.HALF_UP); AssertUtil.assertTrue(transportAmount.compareTo(BigDecimal.ZERO) < 0 || totalAmountTaxEncluded.compareTo(BigDecimal.ZERO) < 0, ErrorCodeEnum.ZY100010004); break; } tempOwnCarServiceFeeTaxEncluded = ownCarServiceFee.divide(new BigDecimal(1).add(tmsTransportSupplierRateItemDO.getTax().divide(new BigDecimal(100))), 4, RoundingMode.HALF_UP); } }这可能是我继最短路径算法以来最恶心的代码了,多次的逻辑变更,其计算场景根本不是适配的,细微点不得不考虑,但问题就是第二天要上线的,临时改需求真的让人头大