Commit 094330778556ce4b9fbde3293fff670865b7555c
1 parent
2f5984af
fix(mall): 修复全局比例分佣商品预估佣金为 0,对应 https://t.zsxq.com/Lsu8i
Showing
3 changed files
with
158 additions
and
47 deletions
yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java
| @@ -38,7 +38,6 @@ import java.util.*; | @@ -38,7 +38,6 @@ import java.util.*; | ||
| 38 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 38 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 39 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; | 39 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; |
| 40 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMinValue; | 40 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMinValue; |
| 41 | -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; | ||
| 42 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH; | 41 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH; |
| 43 | 42 | ||
| 44 | /** | 43 | /** |
| @@ -143,7 +142,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { | @@ -143,7 +142,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { | ||
| 143 | int calculatePrice(Integer basePrice, Integer percent, Integer fixedPrice) { | 142 | int calculatePrice(Integer basePrice, Integer percent, Integer fixedPrice) { |
| 144 | // 1. 优先使用固定佣金 | 143 | // 1. 优先使用固定佣金 |
| 145 | if (fixedPrice != null && fixedPrice >= 0) { | 144 | if (fixedPrice != null && fixedPrice >= 0) { |
| 146 | - return ObjectUtil.defaultIfNull(fixedPrice, 0); | 145 | + return fixedPrice; |
| 147 | } | 146 | } |
| 148 | // 2. 根据比例计算佣金 | 147 | // 2. 根据比例计算佣金 |
| 149 | if (basePrice != null && basePrice > 0 && percent != null && percent > 0) { | 148 | if (basePrice != null && basePrice > 0 && percent != null && percent > 0) { |
| @@ -329,7 +328,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { | @@ -329,7 +328,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { | ||
| 329 | return respVO; | 328 | return respVO; |
| 330 | } | 329 | } |
| 331 | // 2.2 校验用户是否有分销资格 | 330 | // 2.2 校验用户是否有分销资格 |
| 332 | - respVO.setEnabled(brokerageUserService.getUserBrokerageEnabled(getLoginUserId())); | 331 | + respVO.setEnabled(brokerageUserService.getUserBrokerageEnabled(userId)); |
| 333 | if (BooleanUtil.isFalse(respVO.getEnabled())) { | 332 | if (BooleanUtil.isFalse(respVO.getEnabled())) { |
| 334 | return respVO; | 333 | return respVO; |
| 335 | } | 334 | } |
| @@ -339,22 +338,22 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { | @@ -339,22 +338,22 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { | ||
| 339 | return respVO; | 338 | return respVO; |
| 340 | } | 339 | } |
| 341 | 340 | ||
| 342 | - // 3.1 商品单独分佣模式 | ||
| 343 | - Integer fixedMinPrice = 0; | ||
| 344 | - Integer fixedMaxPrice = 0; | ||
| 345 | - Integer spuMinPrice = 0; | ||
| 346 | - Integer spuMaxPrice = 0; | 341 | + // 3.1 获取商品 SKU 列表 |
| 347 | List<ProductSkuRespDTO> skuList = productSkuApi.getSkuListBySpuId(ListUtil.of(spuId)); | 342 | List<ProductSkuRespDTO> skuList = productSkuApi.getSkuListBySpuId(ListUtil.of(spuId)); |
| 348 | if (BooleanUtil.isTrue(spu.getSubCommissionType())) { | 343 | if (BooleanUtil.isTrue(spu.getSubCommissionType())) { |
| 349 | - fixedMinPrice = getMinValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice); | ||
| 350 | - fixedMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice); | ||
| 351 | - // 3.2 全局分佣模式(根据商品价格比例计算) | 344 | + // 3.2.1 商品独立分销模式:直接取 SKU 固定佣金 |
| 345 | + // 注意:固定佣金允许为 0,表示商家主动设为零佣金 | ||
| 346 | + Integer fixedMinPrice = getMinValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice); | ||
| 347 | + Integer fixedMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice); | ||
| 348 | + respVO.setBrokerageMinPrice(calculatePrice(null, tradeConfig.getBrokerageFirstPercent(), fixedMinPrice)) | ||
| 349 | + .setBrokerageMaxPrice(calculatePrice(null, tradeConfig.getBrokerageFirstPercent(), fixedMaxPrice)); | ||
| 352 | } else { | 350 | } else { |
| 353 | - spuMinPrice = getMinValue(skuList, ProductSkuRespDTO::getPrice); | ||
| 354 | - spuMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getPrice); | 351 | + // 3.2.2 全局比例模式:固定佣金传 null,避免被默认值 0 提前拦截 |
| 352 | + Integer spuMinPrice = getMinValue(skuList, ProductSkuRespDTO::getPrice); | ||
| 353 | + Integer spuMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getPrice); | ||
| 354 | + respVO.setBrokerageMinPrice(calculatePrice(spuMinPrice, tradeConfig.getBrokerageFirstPercent(), null)) | ||
| 355 | + .setBrokerageMaxPrice(calculatePrice(spuMaxPrice, tradeConfig.getBrokerageFirstPercent(), null)); | ||
| 355 | } | 356 | } |
| 356 | - respVO.setBrokerageMinPrice(calculatePrice(spuMinPrice, tradeConfig.getBrokerageFirstPercent(), fixedMinPrice)); | ||
| 357 | - respVO.setBrokerageMaxPrice(calculatePrice(spuMaxPrice, tradeConfig.getBrokerageFirstPercent(), fixedMaxPrice)); | ||
| 358 | return respVO; | 357 | return respVO; |
| 359 | } | 358 | } |
| 360 | 359 |
yudao-module-mall/yudao-module-trade/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java
| 1 | package cn.iocoder.yudao.module.trade.service.brokerage; | 1 | package cn.iocoder.yudao.module.trade.service.brokerage; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.ListUtil; | ||
| 3 | import cn.hutool.core.util.NumberUtil; | 4 | import cn.hutool.core.util.NumberUtil; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 7 | +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||
| 8 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 9 | +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | ||
| 10 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | ||
| 6 | import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO; | 11 | import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO; |
| 12 | +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO; | ||
| 7 | import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; | 13 | import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; |
| 14 | +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; | ||
| 8 | import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageRecordMapper; | 15 | import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageRecordMapper; |
| 16 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; | ||
| 17 | +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; | ||
| 9 | import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; | 18 | import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; |
| 10 | import jakarta.annotation.Resource; | 19 | import jakarta.annotation.Resource; |
| 11 | -import org.junit.jupiter.api.Disabled; | ||
| 12 | import org.junit.jupiter.api.Test; | 20 | import org.junit.jupiter.api.Test; |
| 13 | import org.springframework.context.annotation.Import; | 21 | import org.springframework.context.annotation.Import; |
| 14 | import org.springframework.test.context.bean.override.mockito.MockitoBean; | 22 | import org.springframework.test.context.bean.override.mockito.MockitoBean; |
| 15 | 23 | ||
| 16 | import java.math.RoundingMode; | 24 | import java.math.RoundingMode; |
| 25 | +import java.util.List; | ||
| 17 | 26 | ||
| 18 | -import static cn.hutool.core.util.RandomUtil.randomEle; | ||
| 19 | -import static cn.hutool.core.util.RandomUtil.randomInt; | ||
| 20 | import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; | 27 | import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; |
| 28 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; | ||
| 21 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; | 29 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; |
| 22 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | 30 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 23 | -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomInteger; | ||
| 24 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | 31 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 25 | import static org.junit.jupiter.api.Assertions.assertEquals; | 32 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 33 | +import static org.junit.jupiter.api.Assertions.assertTrue; | ||
| 34 | +import static org.mockito.Mockito.when; | ||
| 26 | 35 | ||
| 27 | -// TODO @芋艿:单测后续看看 | ||
| 28 | /** | 36 | /** |
| 29 | * {@link BrokerageRecordServiceImpl} 的单元测试类 | 37 | * {@link BrokerageRecordServiceImpl} 的单元测试类 |
| 30 | * | 38 | * |
| 31 | * @author owen | 39 | * @author owen |
| 32 | */ | 40 | */ |
| 33 | -@Disabled // TODO 芋艿:后续 fix 补充的单测 | ||
| 34 | @Import(BrokerageRecordServiceImpl.class) | 41 | @Import(BrokerageRecordServiceImpl.class) |
| 35 | public class BrokerageRecordServiceImplTest extends BaseDbUnitTest { | 42 | public class BrokerageRecordServiceImplTest extends BaseDbUnitTest { |
| 36 | 43 | ||
| @@ -43,31 +50,43 @@ public class BrokerageRecordServiceImplTest extends BaseDbUnitTest { | @@ -43,31 +50,43 @@ public class BrokerageRecordServiceImplTest extends BaseDbUnitTest { | ||
| 43 | private TradeConfigService tradeConfigService; | 50 | private TradeConfigService tradeConfigService; |
| 44 | @MockitoBean | 51 | @MockitoBean |
| 45 | private BrokerageUserService brokerageUserService; | 52 | private BrokerageUserService brokerageUserService; |
| 53 | + @MockitoBean | ||
| 54 | + private ProductSpuApi productSpuApi; | ||
| 55 | + @MockitoBean | ||
| 56 | + private ProductSkuApi productSkuApi; | ||
| 46 | 57 | ||
| 47 | @Test | 58 | @Test |
| 48 | - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 | ||
| 49 | public void testGetBrokerageRecordPage() { | 59 | public void testGetBrokerageRecordPage() { |
| 50 | // mock 数据 | 60 | // mock 数据 |
| 51 | BrokerageRecordDO dbBrokerageRecord = randomPojo(BrokerageRecordDO.class, o -> { // 等会查询到 | 61 | BrokerageRecordDO dbBrokerageRecord = randomPojo(BrokerageRecordDO.class, o -> { // 等会查询到 |
| 52 | - o.setUserId(null); | ||
| 53 | - o.setBizType(null); | ||
| 54 | - o.setStatus(null); | ||
| 55 | - o.setCreateTime(null); | 62 | + o.setUserId(1L); |
| 63 | + o.setBizType(BrokerageRecordBizTypeEnum.ORDER.getType()); | ||
| 64 | + o.setStatus(BrokerageRecordStatusEnum.SETTLEMENT.getStatus()); | ||
| 65 | + o.setSourceUserLevel(1); | ||
| 66 | + o.setSourceUserId(100L); | ||
| 67 | + o.setCreateTime(buildTime(2023, 2, 10)); | ||
| 68 | + o.setDeleted(false); | ||
| 56 | }); | 69 | }); |
| 57 | brokerageRecordMapper.insert(dbBrokerageRecord); | 70 | brokerageRecordMapper.insert(dbBrokerageRecord); |
| 58 | // 测试 userId 不匹配 | 71 | // 测试 userId 不匹配 |
| 59 | - brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setUserId(null))); | 72 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setUserId(2L))); |
| 60 | // 测试 bizType 不匹配 | 73 | // 测试 bizType 不匹配 |
| 61 | - brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setBizType(null))); | 74 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, |
| 75 | + o -> o.setBizType(BrokerageRecordBizTypeEnum.WITHDRAW.getType()))); | ||
| 62 | // 测试 status 不匹配 | 76 | // 测试 status 不匹配 |
| 63 | - brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setStatus(null))); | 77 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, |
| 78 | + o -> o.setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus()))); | ||
| 79 | + // 测试 sourceUserLevel 不匹配 | ||
| 80 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setSourceUserLevel(2))); | ||
| 64 | // 测试 createTime 不匹配 | 81 | // 测试 createTime 不匹配 |
| 65 | - brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setCreateTime(null))); | 82 | + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, |
| 83 | + o -> o.setCreateTime(buildTime(2023, 3, 1)))); | ||
| 66 | // 准备参数 | 84 | // 准备参数 |
| 67 | BrokerageRecordPageReqVO reqVO = new BrokerageRecordPageReqVO(); | 85 | BrokerageRecordPageReqVO reqVO = new BrokerageRecordPageReqVO(); |
| 68 | - reqVO.setUserId(null); | ||
| 69 | - reqVO.setBizType(null); | ||
| 70 | - reqVO.setStatus(null); | 86 | + reqVO.setUserId(1L); |
| 87 | + reqVO.setBizType(BrokerageRecordBizTypeEnum.ORDER.getType()); | ||
| 88 | + reqVO.setStatus(BrokerageRecordStatusEnum.SETTLEMENT.getStatus()); | ||
| 89 | + reqVO.setSourceUserLevel(1); | ||
| 71 | reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); | 90 | reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); |
| 72 | 91 | ||
| 73 | // 调用 | 92 | // 调用 |
| @@ -81,37 +100,128 @@ public class BrokerageRecordServiceImplTest extends BaseDbUnitTest { | @@ -81,37 +100,128 @@ public class BrokerageRecordServiceImplTest extends BaseDbUnitTest { | ||
| 81 | @Test | 100 | @Test |
| 82 | public void testCalculatePrice_useFixedPrice() { | 101 | public void testCalculatePrice_useFixedPrice() { |
| 83 | // mock 数据 | 102 | // mock 数据 |
| 84 | - Integer payPrice = randomInteger(); | ||
| 85 | - Integer percent = randomInt(1, 101); | ||
| 86 | - Integer fixedPrice = randomInt(); | 103 | + Integer payPrice = 1000; |
| 104 | + Integer percent = 10; | ||
| 105 | + Integer fixedPrice = 88; | ||
| 87 | // 调用 | 106 | // 调用 |
| 88 | int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); | 107 | int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); |
| 89 | // 断言 | 108 | // 断言 |
| 90 | - assertEquals(brokerage, fixedPrice); | 109 | + assertEquals(fixedPrice, brokerage); |
| 91 | } | 110 | } |
| 92 | 111 | ||
| 93 | @Test | 112 | @Test |
| 94 | public void testCalculatePrice_usePercent() { | 113 | public void testCalculatePrice_usePercent() { |
| 95 | - // mock 数据 | ||
| 96 | - Integer payPrice = randomInteger(); | ||
| 97 | - Integer percent = randomInt(1, 101); | ||
| 98 | - Integer fixedPrice = randomEle(new Integer[]{0, null}); | ||
| 99 | - System.out.println("fixedPrice=" + fixedPrice); | 114 | + // mock 数据:fixedPrice 为 null 时,按比例计算佣金 |
| 115 | + Integer payPrice = 1000; | ||
| 116 | + Integer percent = 10; | ||
| 117 | + Integer fixedPrice = null; | ||
| 100 | // 调用 | 118 | // 调用 |
| 101 | int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); | 119 | int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); |
| 102 | // 断言 | 120 | // 断言 |
| 103 | - assertEquals(brokerage, NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, RoundingMode.DOWN).intValue()); | 121 | + assertEquals(NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, |
| 122 | + RoundingMode.DOWN).intValue(), brokerage); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + @Test | ||
| 126 | + public void testCalculatePrice_fixedPriceIsZero() { | ||
| 127 | + // mock 数据:fixedPrice 为 0 时,仍使用固定佣金,不回退到比例计算 | ||
| 128 | + Integer payPrice = 1000; | ||
| 129 | + Integer percent = 10; | ||
| 130 | + Integer fixedPrice = 0; | ||
| 131 | + // 调用 | ||
| 132 | + int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); | ||
| 133 | + // 断言 | ||
| 134 | + assertEquals(0, brokerage); | ||
| 104 | } | 135 | } |
| 105 | 136 | ||
| 106 | @Test | 137 | @Test |
| 107 | public void testCalculatePrice_equalsZero() { | 138 | public void testCalculatePrice_equalsZero() { |
| 108 | - // mock 数据 | 139 | + // mock 数据:三个参数均无效时,返回 0 |
| 109 | Integer payPrice = null; | 140 | Integer payPrice = null; |
| 110 | Integer percent = null; | 141 | Integer percent = null; |
| 111 | Integer fixedPrice = null; | 142 | Integer fixedPrice = null; |
| 112 | // 调用 | 143 | // 调用 |
| 113 | int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); | 144 | int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); |
| 114 | // 断言 | 145 | // 断言 |
| 115 | - assertEquals(brokerage, 0); | 146 | + assertEquals(0, brokerage); |
| 147 | + } | ||
| 148 | + | ||
| 149 | + @Test | ||
| 150 | + public void testCalculateProductBrokeragePrice_globalPercent() { | ||
| 151 | + // mock:分销功能已开启,比例 10%,当前用户有分销资格 | ||
| 152 | + TradeConfigDO tradeConfig = new TradeConfigDO(); | ||
| 153 | + tradeConfig.setBrokerageEnabled(true); | ||
| 154 | + tradeConfig.setBrokerageFirstPercent(10); | ||
| 155 | + when(tradeConfigService.getTradeConfig()).thenReturn(tradeConfig); | ||
| 156 | + when(brokerageUserService.getUserBrokerageEnabled(100L)).thenReturn(true); | ||
| 157 | + | ||
| 158 | + // mock:商品未开启独立分销(subCommissionType = false),SKU 售价 1000 分 | ||
| 159 | + ProductSpuRespDTO spu = new ProductSpuRespDTO(); | ||
| 160 | + spu.setSubCommissionType(false); | ||
| 161 | + when(productSpuApi.getSpu(1L)).thenReturn(spu); | ||
| 162 | + | ||
| 163 | + ProductSkuRespDTO sku = new ProductSkuRespDTO(); | ||
| 164 | + sku.setPrice(1000); | ||
| 165 | + when(productSkuApi.getSkuListBySpuId(ListUtil.of(1L))).thenReturn(List.of(sku)); | ||
| 166 | + | ||
| 167 | + // 调用 | ||
| 168 | + AppBrokerageProductPriceRespVO result = brokerageRecordService.calculateProductBrokeragePrice(100L, 1L); | ||
| 169 | + | ||
| 170 | + // 断言:按 10% 比例计算,1000 * 10% = 100 分(向下取整) | ||
| 171 | + assertTrue(result.getEnabled()); | ||
| 172 | + assertEquals(100, result.getBrokerageMinPrice()); | ||
| 173 | + assertEquals(100, result.getBrokerageMaxPrice()); | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + @Test | ||
| 177 | + public void testCalculateProductBrokeragePrice_subCommissionZeroFixed() { | ||
| 178 | + // mock:分销功能已开启,比例 10%,当前用户有分销资格 | ||
| 179 | + TradeConfigDO tradeConfig = new TradeConfigDO(); | ||
| 180 | + tradeConfig.setBrokerageEnabled(true); | ||
| 181 | + tradeConfig.setBrokerageFirstPercent(10); | ||
| 182 | + when(tradeConfigService.getTradeConfig()).thenReturn(tradeConfig); | ||
| 183 | + when(brokerageUserService.getUserBrokerageEnabled(100L)).thenReturn(true); | ||
| 184 | + | ||
| 185 | + // mock:商品开启独立分销(subCommissionType = true),SKU 固定佣金为 0(商家主动设置) | ||
| 186 | + ProductSpuRespDTO spu = new ProductSpuRespDTO(); | ||
| 187 | + spu.setSubCommissionType(true); | ||
| 188 | + when(productSpuApi.getSpu(2L)).thenReturn(spu); | ||
| 189 | + | ||
| 190 | + ProductSkuRespDTO sku = new ProductSkuRespDTO(); | ||
| 191 | + sku.setPrice(1000); | ||
| 192 | + sku.setFirstBrokeragePrice(0); | ||
| 193 | + when(productSkuApi.getSkuListBySpuId(ListUtil.of(2L))).thenReturn(List.of(sku)); | ||
| 194 | + | ||
| 195 | + // 调用 | ||
| 196 | + AppBrokerageProductPriceRespVO result = brokerageRecordService.calculateProductBrokeragePrice(100L, 2L); | ||
| 197 | + | ||
| 198 | + // 断言:独立分销固定佣金为 0,应返回 0,不得回退到全局比例 | ||
| 199 | + assertTrue(result.getEnabled()); | ||
| 200 | + assertEquals(0, result.getBrokerageMinPrice()); | ||
| 201 | + assertEquals(0, result.getBrokerageMaxPrice()); | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + @Test | ||
| 205 | + public void testCalculateProductBrokeragePrice_subCommissionEmptySkuList() { | ||
| 206 | + // mock:分销功能已开启,比例 10%,当前用户有分销资格 | ||
| 207 | + TradeConfigDO tradeConfig = new TradeConfigDO(); | ||
| 208 | + tradeConfig.setBrokerageEnabled(true); | ||
| 209 | + tradeConfig.setBrokerageFirstPercent(10); | ||
| 210 | + when(tradeConfigService.getTradeConfig()).thenReturn(tradeConfig); | ||
| 211 | + when(brokerageUserService.getUserBrokerageEnabled(100L)).thenReturn(true); | ||
| 212 | + | ||
| 213 | + // mock:商品开启独立分销,但查询不到 SKU 固定佣金 | ||
| 214 | + ProductSpuRespDTO spu = new ProductSpuRespDTO(); | ||
| 215 | + spu.setSubCommissionType(true); | ||
| 216 | + when(productSpuApi.getSpu(3L)).thenReturn(spu); | ||
| 217 | + when(productSkuApi.getSkuListBySpuId(ListUtil.of(3L))).thenReturn(List.of()); | ||
| 218 | + | ||
| 219 | + // 调用 | ||
| 220 | + AppBrokerageProductPriceRespVO result = brokerageRecordService.calculateProductBrokeragePrice(100L, 3L); | ||
| 221 | + | ||
| 222 | + // 断言:独立分销没有固定佣金时,不回退到全局比例 | ||
| 223 | + assertTrue(result.getEnabled()); | ||
| 224 | + assertEquals(0, result.getBrokerageMinPrice()); | ||
| 225 | + assertEquals(0, result.getBrokerageMaxPrice()); | ||
| 116 | } | 226 | } |
| 117 | } | 227 | } |
yudao-module-mall/yudao-module-trade/src/test/resources/sql/create_tables.sql
| @@ -173,7 +173,7 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_user" | @@ -173,7 +173,7 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_user" | ||
| 173 | ) COMMENT '分销用户'; | 173 | ) COMMENT '分销用户'; |
| 174 | CREATE TABLE IF NOT EXISTS "trade_brokerage_record" | 174 | CREATE TABLE IF NOT EXISTS "trade_brokerage_record" |
| 175 | ( | 175 | ( |
| 176 | - "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY, | 176 | + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, |
| 177 | "user_id" bigint NOT NULL, | 177 | "user_id" bigint NOT NULL, |
| 178 | "biz_id" varchar NOT NULL, | 178 | "biz_id" varchar NOT NULL, |
| 179 | "biz_type" varchar NOT NULL, | 179 | "biz_type" varchar NOT NULL, |
| @@ -184,6 +184,8 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_record" | @@ -184,6 +184,8 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_record" | ||
| 184 | "status" varchar NOT NULL, | 184 | "status" varchar NOT NULL, |
| 185 | "frozen_days" int NOT NULL, | 185 | "frozen_days" int NOT NULL, |
| 186 | "unfreeze_time" varchar, | 186 | "unfreeze_time" varchar, |
| 187 | + "source_user_level" int, | ||
| 188 | + "source_user_id" bigint, | ||
| 187 | "creator" varchar DEFAULT '', | 189 | "creator" varchar DEFAULT '', |
| 188 | "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | 190 | "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, |
| 189 | "updater" varchar DEFAULT '', | 191 | "updater" varchar DEFAULT '', |
| @@ -232,4 +234,4 @@ CREATE TABLE IF NOT EXISTS "trade_delivery_express" | @@ -232,4 +234,4 @@ CREATE TABLE IF NOT EXISTS "trade_delivery_express" | ||
| 232 | "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | 234 | "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
| 233 | "deleted" bit NOT NULL DEFAULT FALSE, | 235 | "deleted" bit NOT NULL DEFAULT FALSE, |
| 234 | PRIMARY KEY ("id") | 236 | PRIMARY KEY ("id") |
| 235 | -) COMMENT '佣金提现'; | ||
| 236 | \ No newline at end of file | 237 | \ No newline at end of file |
| 238 | +) COMMENT '佣金提现'; |