spec.md 2.7 KB

积分计算优化 Spec

Why

积分相关代码存在多个精度和计算正确性问题:积分发放使用 ROUND_CEILING(进位取整)而非用户要求的四舍五入;多店铺积分分摊使用 double 算术存在浮点精度风险;preAllocatedIntegral 使用 Double 类型不符合积分必须为整数的约束;多店铺分摊中 cap 修正后未回写累计值导致最后一个店铺减法兜底结果错误。

What Changes

  • 积分发放取整方式从 ROUND_CEILING 改为 ROUND_HALF_UP(四舍五入)
  • FsStoreOrderComputedParam.preAllocatedIntegral 类型从 Double 改为 Integer
  • computedOrders 中积分分摊计算全部改用 BigDecimal 算术,消除 double 精度风险
  • 修复多店铺分摊中 subDeduction 超限 cap 后未更新 allocatedDeductionSum / allocatedIntegralSum 的 bug
  • user.getIntegral().intValue() 改为 longValue()totalIntegral 改为 long 类型,避免大值截断
  • totalDeduction 计算改用 BigDecimal.divide 确保精度

Impact

  • Affected code: FsUserIntegralLogsServiceImpl.javaFsStoreOrderScrmServiceImpl.javaFsStoreOrderComputedParam.java
  • 不影响旧的单店铺积分逻辑(computedOrder / store.integral 配置)
  • 不影响退款积分逻辑(refundIntegral
  • preAllocatedIntegral 类型变更需同步修改 computedOrderscomputedOrderMultiStore 中的使用

MODIFIED Requirements

Requirement: 积分发放取整

积分发放时,amount × rate 的结果 SHALL 使用 RoundingMode.HALF_UP(四舍五入)取整,不得使用 ROUND_CEILING(进位取整)。

Scenario: 正常发放

  • WHEN 消费金额为 10.5 元,发放比例为 0.1(1元=0.1积分)
  • THEN 计算结果 1.05 → 四舍五入为 1 积分(非进位取整的 2)

Requirement: 多店铺积分分摊计算精度

多店铺积分分摊 SHALL 全程使用 BigDecimal 算术,禁止使用 double 中间运算。积分值 SHALL 始终为整数,不得出现小数。

Scenario: 比例分摊

  • WHEN 合计 100 元,子订单 A=95 元、B=5 元,总积分 100
  • THEN A 分摊 95 积分,B 分摊 5 积分(最后一个用总计减去已分配)

Scenario: 超限 cap 后累计值修正

  • WHEN 子订单分摊的抵扣金额超过该子订单应付金额时
  • THEN cap 后的值 SHALL 回写到 allocatedDeductionSumallocatedIntegralSum,确保最后一个店铺的减法兜底结果正确

Requirement: preAllocatedIntegral 类型

FsStoreOrderComputedParam.preAllocatedIntegral SHALL 为 Integer 类型,不得使用 Double

Requirement: 用户积分取值精度

读取用户积分余额时 SHALL 使用 longValue(),不得使用 intValue() 以防大值截断。