1、保存订单商品,2、验证参数是否合法

This commit is contained in:
2025-07-30 01:32:10 +08:00
parent 1bda2263c0
commit d3904420a9
10 changed files with 1041 additions and 15 deletions

View File

@@ -39,12 +39,12 @@ public class OrderConfigProperties {
* 测试手机号列表
*/
private List<String> phoneNumbers;
/**
* 测试支付金额
*/
private BigDecimal testPayAmount = new BigDecimal("0.01");
/**
* 是否启用测试模式
*/
@@ -57,22 +57,22 @@ public class OrderConfigProperties {
* 租户ID
*/
private Integer tenantId;
/**
* 租户名称
*/
private String tenantName;
/**
* 最小金额限制
*/
private BigDecimal minAmount;
/**
* 金额限制提示信息
*/
private String minAmountMessage;
/**
* 是否启用
*/
@@ -81,16 +81,22 @@ public class OrderConfigProperties {
@Data
public static class DefaultConfig {
/**
* 默认标题
*/
private String defaultTitle = "订单标题";
/**
* 默认备注
*/
private String defaultComments = "暂无";
/**
* 最小订单金额
*/
private BigDecimal minOrderAmount = BigDecimal.ZERO;
/**
* 订单超时时间(分钟)
*/
@@ -101,8 +107,8 @@ public class OrderConfigProperties {
* 检查是否为测试账号
*/
public boolean isTestAccount(String phone) {
return testAccount.isEnabled() &&
testAccount.getPhoneNumbers() != null &&
return testAccount.isEnabled() &&
testAccount.getPhoneNumbers() != null &&
testAccount.getPhoneNumbers().contains(phone);
}

View File

@@ -1,11 +1,12 @@
package com.gxwebsoft.shop.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.List;
/**
* 订单创建请求DTO
@@ -23,6 +24,10 @@ public class OrderCreateRequest {
@Max(value = 2, message = "订单类型值无效")
private Integer type;
@Size(max = 60, message = "备注长度不能超过60个字符")
@Schema(description = "订单标题")
private String title;
@Schema(description = "快递/自提")
private Integer deliveryType;
@@ -44,9 +49,15 @@ public class OrderCreateRequest {
@Schema(description = "使用的会员卡id")
private String cardId;
@Schema(description = "关联收货地址")
private Integer addressId;
@Schema(description = "收货地址")
private String address;
@Schema(description = "收货人姓名")
private String realName;
@Schema(description = "地址纬度")
private String addressLat;
@@ -129,4 +140,28 @@ public class OrderCreateRequest {
@Schema(description = "租户id")
@NotNull(message = "租户ID不能为空")
private Integer tenantId;
@Schema(description = "订单商品列表")
@Valid
@NotEmpty(message = "订单商品列表不能为空")
private List<OrderGoodsItem> goodsItems;
/**
* 订单商品项
*/
@Data
@Schema(name = "OrderGoodsItem", description = "订单商品项")
public static class OrderGoodsItem {
@Schema(description = "商品ID", required = true)
@NotNull(message = "商品ID不能为空")
private Integer goodsId;
@Schema(description = "商品数量", required = true)
@NotNull(message = "商品数量不能为空")
@Min(value = 1, message = "商品数量必须大于0")
private Integer quantity;
@Schema(description = "支付类型")
private Integer payType;
}
}

View File

@@ -40,6 +40,9 @@ public class ShopOrder implements Serializable {
@Schema(description = "订单类型0商城订单 1预定订单/外卖 2会员卡")
private Integer type;
@Schema(description = "订单标题")
private String title;
@Schema(description = "快递/自提")
private Integer deliveryType;
@@ -218,7 +221,6 @@ public class ShopOrder implements Serializable {
private String nickname;
@Schema(description = "真实姓名")
@TableField(exist = false)
private String realName;
@Schema(description = "手机号码")

View File

@@ -5,14 +5,19 @@ import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.config.OrderConfigProperties;
import com.gxwebsoft.shop.dto.OrderCreateRequest;
import com.gxwebsoft.shop.entity.ShopGoods;
import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.shop.entity.ShopOrderGoods;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
@@ -29,6 +34,12 @@ public class OrderBusinessService {
@Resource
private ShopOrderService shopOrderService;
@Resource
private ShopOrderGoodsService shopOrderGoodsService;
@Resource
private ShopGoodsService shopGoodsService;
@Resource
private OrderConfigProperties orderConfig;
@@ -41,6 +52,7 @@ public class OrderBusinessService {
*/
@Transactional(rollbackFor = Exception.class)
public Map<String, String> createOrder(OrderCreateRequest request, User loginUser) {
// 1. 参数校验
validateOrderRequest(request, loginUser);
@@ -56,7 +68,10 @@ public class OrderBusinessService {
throw new BusinessException("订单保存失败");
}
// 5. 创建微信支付订单
// 5. 保存订单商品
saveOrderGoods(request, shopOrder);
// 6. 创建微信支付订单
try {
return shopOrderService.createWxOrder(shopOrder);
} catch (Exception e) {
@@ -73,19 +88,92 @@ public class OrderBusinessService {
throw new BusinessException("用户未登录");
}
if (request.getTotalPrice() == null || request.getTotalPrice().compareTo(BigDecimal.ZERO) <= 0) {
// 验证商品信息并计算总金额
BigDecimal calculatedTotal = validateAndCalculateTotal(request);
if (calculatedTotal.compareTo(BigDecimal.ZERO) <= 0) {
throw new BusinessException("商品金额不能为0");
}
// 检查前端传入的总金额是否正确允许小的误差比如0.01
if (request.getTotalPrice() != null &&
request.getTotalPrice().subtract(calculatedTotal).abs().compareTo(new BigDecimal("0.01")) > 0) {
log.warn("订单金额计算不一致,前端传入:{},后台计算:{}", request.getTotalPrice(), calculatedTotal);
throw new BusinessException("订单金额计算错误,请刷新重试");
}
// 使用后台计算的金额
request.setTotalPrice(calculatedTotal);
// 检查租户特殊规则
OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(request.getTenantId());
if (tenantRule != null && tenantRule.getMinAmount() != null) {
if (request.getTotalPrice().compareTo(tenantRule.getMinAmount()) < 0) {
if (calculatedTotal.compareTo(tenantRule.getMinAmount()) < 0) {
throw new BusinessException(tenantRule.getMinAmountMessage());
}
}
}
/**
* 验证商品信息并计算总金额
*/
private BigDecimal validateAndCalculateTotal(OrderCreateRequest request) {
if (CollectionUtils.isEmpty(request.getGoodsItems())) {
throw new BusinessException("订单商品列表不能为空");
}
BigDecimal total = BigDecimal.ZERO;
for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) {
// 验证商品ID
if (item.getGoodsId() == null) {
throw new BusinessException("商品ID不能为空");
}
// 验证购买数量
if (item.getQuantity() == null || item.getQuantity() <= 0) {
throw new BusinessException("商品购买数量必须大于0");
}
// 获取商品信息
ShopGoods goods = shopGoodsService.getById(item.getGoodsId());
if (goods == null) {
throw new BusinessException("商品不存在商品ID" + item.getGoodsId());
}
// 验证商品状态
if (goods.getStatus() == null || goods.getStatus() != 0) {
throw new BusinessException("商品已下架:" + goods.getName());
}
// 验证商品价格
if (goods.getPrice() == null || goods.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
throw new BusinessException("商品价格异常:" + goods.getName());
}
// 验证库存(如果商品有库存管理)
if (goods.getStock() != null && goods.getStock() < item.getQuantity()) {
throw new BusinessException("商品库存不足:" + goods.getName() + ",当前库存:" + goods.getStock());
}
// 验证购买数量限制
if (goods.getCanBuyNumber() != null && goods.getCanBuyNumber() > 0 &&
item.getQuantity() > goods.getCanBuyNumber()) {
throw new BusinessException("商品购买数量超过限制:" + goods.getName() + ",最大购买数量:" + goods.getCanBuyNumber());
}
// 计算商品小计
BigDecimal itemTotal = goods.getPrice().multiply(new BigDecimal(item.getQuantity()));
total = total.add(itemTotal);
log.debug("商品验证通过 - ID{},名称:{},单价:{},数量:{},小计:{}",
goods.getGoodsId(), goods.getName(), goods.getPrice(), item.getQuantity(), itemTotal);
}
log.info("订单商品验证完成,总金额:{}", total);
return total;
}
/**
* 构建订单对象
*/
@@ -148,6 +236,79 @@ public class OrderBusinessService {
}
}
/**
* 保存订单商品
*/
private void saveOrderGoods(OrderCreateRequest request, ShopOrder shopOrder) {
if (CollectionUtils.isEmpty(request.getGoodsItems())) {
log.warn("订单商品列表为空,订单号:{}", shopOrder.getOrderNo());
return;
}
List<ShopOrderGoods> orderGoodsList = new ArrayList<>();
for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) {
// 重新获取商品信息(确保数据一致性)
ShopGoods goods = shopGoodsService.getById(item.getGoodsId());
if (goods == null) {
throw new BusinessException("商品不存在商品ID" + item.getGoodsId());
}
// 再次验证商品状态(防止并发问题)
if (goods.getStatus() == null || goods.getStatus() != 0) {
throw new BusinessException("商品已下架:" + goods.getName());
}
ShopOrderGoods orderGoods = new ShopOrderGoods();
// 设置订单关联信息
orderGoods.setOrderId(shopOrder.getOrderId());
orderGoods.setOrderCode(shopOrder.getOrderNo());
// 设置商户信息
orderGoods.setMerchantId(shopOrder.getMerchantId());
orderGoods.setMerchantName(shopOrder.getMerchantName());
// 设置商品信息(使用后台查询的真实数据)
orderGoods.setGoodsId(item.getGoodsId());
orderGoods.setGoodsName(goods.getName());
orderGoods.setImage(goods.getImage());
orderGoods.setPrice(goods.getPrice()); // 使用后台查询的价格
orderGoods.setTotalNum(item.getQuantity());
// 计算商品小计(用于日志记录)
BigDecimal itemTotal = goods.getPrice().multiply(new BigDecimal(item.getQuantity()));
// 设置商品规格信息(如果有的话)
if (goods.getCode() != null) {
orderGoods.setSpec(goods.getCode()); // 使用商品编码作为规格
}
// 设置支付相关信息
orderGoods.setPayStatus(0); // 0 未付款
orderGoods.setOrderStatus(0); // 0 未使用
orderGoods.setIsFree(false); // 默认收费
orderGoods.setVersion(0); // 当前版本
// 设置其他信息
orderGoods.setComments(request.getComments());
orderGoods.setUserId(shopOrder.getUserId());
orderGoods.setTenantId(shopOrder.getTenantId());
orderGoodsList.add(orderGoods);
log.debug("准备保存订单商品 - 商品ID{},名称:{},单价:{},数量:{},小计:{}",
goods.getGoodsId(), goods.getName(), goods.getPrice(), item.getQuantity(), itemTotal);
}
// 批量保存订单商品
boolean saved = shopOrderGoodsService.saveBatch(orderGoodsList);
if (!saved) {
throw new BusinessException("保存订单商品失败");
}
log.info("成功保存订单商品,订单号:{},商品数量:{}", shopOrder.getOrderNo(), orderGoodsList.size());
}
/**
* 检查是否为测试账号
*/

View File

@@ -135,6 +135,7 @@ shop:
# 默认配置
default-config:
default-title: "订单名称"
default-comments: "暂无"
min-order-amount: 0
order-timeout-minutes: 30

View File

@@ -0,0 +1,170 @@
package com.gxwebsoft.shop;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.dto.OrderCreateRequest;
import com.gxwebsoft.shop.entity.ShopGoods;
import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.shop.entity.ShopOrderGoods;
import com.gxwebsoft.shop.service.OrderBusinessService;
import com.gxwebsoft.shop.service.ShopGoodsService;
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
import com.gxwebsoft.shop.service.ShopOrderService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
/**
* 订单业务服务测试类
*
* @author 科技小王子
* @since 2025-01-26
*/
@ExtendWith(MockitoExtension.class)
public class OrderBusinessServiceTest {
@Mock
private ShopOrderService shopOrderService;
@Mock
private ShopOrderGoodsService shopOrderGoodsService;
@Mock
private ShopGoodsService shopGoodsService;
@InjectMocks
private OrderBusinessService orderBusinessService;
private User testUser;
private OrderCreateRequest testRequest;
private ShopGoods testGoods;
@BeforeEach
void setUp() {
// 准备测试用户
testUser = new User();
testUser.setUserId(1);
testUser.setOpenid("test_openid");
testUser.setPhone("13800138000");
// 准备测试商品
testGoods = new ShopGoods();
testGoods.setGoodsId(10018);
testGoods.setName("科技小王子大米年卡套餐2.5kg");
testGoods.setPrice(new BigDecimal("99.00"));
testGoods.setImage("test_image.jpg");
// 准备测试订单请求
testRequest = new OrderCreateRequest();
testRequest.setType(0);
testRequest.setTotalPrice(new BigDecimal("99.00"));
testRequest.setPayPrice(new BigDecimal("99.00"));
testRequest.setTotalNum(1);
testRequest.setPayType(1);
testRequest.setTenantId(1);
testRequest.setAddressId(10832);
testRequest.setComments("科技小王子大米年卡套餐2.5kg");
testRequest.setDeliveryType(0);
// 准备商品项列表
OrderCreateRequest.OrderGoodsItem goodsItem = new OrderCreateRequest.OrderGoodsItem();
goodsItem.setGoodsId(10018);
goodsItem.setQuantity(1);
goodsItem.setPayType(1);
testRequest.setGoodsItems(Arrays.asList(goodsItem));
}
@Test
void testCreateOrderWithGoods() {
// Mock 商品查询
when(shopGoodsService.getById(10018)).thenReturn(testGoods);
// Mock 订单保存
when(shopOrderService.save(any(ShopOrder.class))).thenAnswer(invocation -> {
ShopOrder order = invocation.getArgument(0);
order.setOrderId(1); // 模拟数据库生成的ID
return true;
});
// Mock 订单商品批量保存
when(shopOrderGoodsService.saveBatch(anyList())).thenReturn(true);
// Mock 微信支付订单创建
HashMap<String, String> wxOrderInfo = new HashMap<>();
wxOrderInfo.put("prepay_id", "test_prepay_id");
when(shopOrderService.createWxOrder(any(ShopOrder.class))).thenReturn(wxOrderInfo);
// 执行测试
Map<String, String> result = orderBusinessService.createOrder(testRequest, testUser);
// 验证结果
assert result != null;
assert result.containsKey("prepay_id");
// 验证方法调用
verify(shopGoodsService, times(1)).getById(10018);
verify(shopOrderService, times(1)).save(any(ShopOrder.class));
verify(shopOrderGoodsService, times(1)).saveBatch(anyList());
verify(shopOrderService, times(1)).createWxOrder(any(ShopOrder.class));
}
@Test
void testCreateOrderWithMultipleGoods() {
// 准备多个商品项
OrderCreateRequest.OrderGoodsItem goodsItem1 = new OrderCreateRequest.OrderGoodsItem();
goodsItem1.setGoodsId(10018);
goodsItem1.setQuantity(1);
goodsItem1.setPayType(1);
OrderCreateRequest.OrderGoodsItem goodsItem2 = new OrderCreateRequest.OrderGoodsItem();
goodsItem2.setGoodsId(10019);
goodsItem2.setQuantity(2);
goodsItem2.setPayType(1);
testRequest.setGoodsItems(Arrays.asList(goodsItem1, goodsItem2));
testRequest.setTotalPrice(new BigDecimal("297.00")); // 99 + 99*2
// Mock 商品查询
when(shopGoodsService.getById(10018)).thenReturn(testGoods);
ShopGoods testGoods2 = new ShopGoods();
testGoods2.setGoodsId(10019);
testGoods2.setName("测试商品2");
testGoods2.setPrice(new BigDecimal("99.00"));
testGoods2.setImage("test_image2.jpg");
when(shopGoodsService.getById(10019)).thenReturn(testGoods2);
// Mock 其他服务
when(shopOrderService.save(any(ShopOrder.class))).thenAnswer(invocation -> {
ShopOrder order = invocation.getArgument(0);
order.setOrderId(1);
return true;
});
when(shopOrderGoodsService.saveBatch(anyList())).thenReturn(true);
when(shopOrderService.createWxOrder(any(ShopOrder.class))).thenReturn(new HashMap<>());
// 执行测试
orderBusinessService.createOrder(testRequest, testUser);
// 验证商品查询次数
verify(shopGoodsService, times(1)).getById(10018);
verify(shopGoodsService, times(1)).getById(10019);
// 验证保存的商品项数量
verify(shopOrderGoodsService, times(1)).saveBatch(argThat(list ->
((List<ShopOrderGoods>) list).size() == 2
));
}
}

View File

@@ -0,0 +1,243 @@
package com.gxwebsoft.shop;
import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.config.OrderConfigProperties;
import com.gxwebsoft.shop.dto.OrderCreateRequest;
import com.gxwebsoft.shop.entity.ShopGoods;
import com.gxwebsoft.shop.service.OrderBusinessService;
import com.gxwebsoft.shop.service.ShopGoodsService;
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
import com.gxwebsoft.shop.service.ShopOrderService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* 订单验证测试类
* 测试商品信息后台验证逻辑
*/
@ExtendWith(MockitoExtension.class)
class OrderValidationTest {
@Mock
private ShopOrderService shopOrderService;
@Mock
private ShopOrderGoodsService shopOrderGoodsService;
@Mock
private ShopGoodsService shopGoodsService;
@Mock
private OrderConfigProperties orderConfig;
@InjectMocks
private OrderBusinessService orderBusinessService;
private User testUser;
private OrderCreateRequest testRequest;
private ShopGoods testGoods;
@BeforeEach
void setUp() {
// 准备测试用户
testUser = new User();
testUser.setUserId(1);
testUser.setNickname("测试用户");
testUser.setPhone("13800138000");
// 准备测试商品
testGoods = new ShopGoods();
testGoods.setGoodsId(10018);
testGoods.setName("测试商品");
testGoods.setPrice(new BigDecimal("99.00"));
testGoods.setStatus(0); // 上架状态
testGoods.setStock(100); // 库存100
testGoods.setCanBuyNumber(10); // 最大购买数量10
testGoods.setCode("TEST001");
// 准备测试订单请求
testRequest = new OrderCreateRequest();
testRequest.setType(0);
testRequest.setTitle("测试订单");
testRequest.setTotalPrice(new BigDecimal("99.00"));
testRequest.setTenantId(1);
// 准备商品项
OrderCreateRequest.OrderGoodsItem goodsItem = new OrderCreateRequest.OrderGoodsItem();
goodsItem.setGoodsId(10018);
goodsItem.setQuantity(1);
testRequest.setGoodsItems(Arrays.asList(goodsItem));
}
@Test
void testValidateOrderRequest_Success() {
// Mock 商品查询
when(shopGoodsService.getById(10018)).thenReturn(testGoods);
when(orderConfig.getTenantRule(1)).thenReturn(null);
// 执行验证 - 应该成功
assertDoesNotThrow(() -> {
// 使用反射调用私有方法进行测试
java.lang.reflect.Method method = OrderBusinessService.class
.getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
method.setAccessible(true);
method.invoke(orderBusinessService, testRequest, testUser);
});
// 验证总金额被正确设置
assertEquals(new BigDecimal("99.00"), testRequest.getTotalPrice());
}
@Test
void testValidateOrderRequest_GoodsNotFound() {
// Mock 商品不存在
when(shopGoodsService.getById(10018)).thenReturn(null);
// 执行验证 - 应该抛出异常
Exception exception = assertThrows(Exception.class, () -> {
java.lang.reflect.Method method = OrderBusinessService.class
.getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
method.setAccessible(true);
method.invoke(orderBusinessService, testRequest, testUser);
});
// 检查是否是 InvocationTargetException 包装的 BusinessException
assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
Throwable cause = exception.getCause();
assertTrue(cause instanceof BusinessException);
assertTrue(cause.getMessage().contains("商品不存在"));
}
@Test
void testValidateOrderRequest_GoodsOffShelf() {
// 设置商品为下架状态
testGoods.setStatus(1);
when(shopGoodsService.getById(10018)).thenReturn(testGoods);
// 执行验证 - 应该抛出异常
Exception exception = assertThrows(Exception.class, () -> {
java.lang.reflect.Method method = OrderBusinessService.class
.getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
method.setAccessible(true);
method.invoke(orderBusinessService, testRequest, testUser);
});
// 检查是否是 InvocationTargetException 包装的 BusinessException
assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
Throwable cause = exception.getCause();
assertTrue(cause instanceof BusinessException);
assertTrue(cause.getMessage().contains("商品已下架"));
}
@Test
void testValidateOrderRequest_InsufficientStock() {
// 设置库存不足
testGoods.setStock(0);
when(shopGoodsService.getById(10018)).thenReturn(testGoods);
// 执行验证 - 应该抛出异常
Exception exception = assertThrows(Exception.class, () -> {
java.lang.reflect.Method method = OrderBusinessService.class
.getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
method.setAccessible(true);
method.invoke(orderBusinessService, testRequest, testUser);
});
// 检查是否是 InvocationTargetException 包装的 BusinessException
assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
Throwable cause = exception.getCause();
assertTrue(cause instanceof BusinessException);
assertTrue(cause.getMessage().contains("商品库存不足"));
}
@Test
void testValidateOrderRequest_ExceedBuyLimit() {
// 设置购买数量超过限制
testRequest.getGoodsItems().get(0).setQuantity(15); // 超过最大购买数量10
when(shopGoodsService.getById(10018)).thenReturn(testGoods);
// 执行验证 - 应该抛出异常
Exception exception = assertThrows(Exception.class, () -> {
java.lang.reflect.Method method = OrderBusinessService.class
.getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
method.setAccessible(true);
method.invoke(orderBusinessService, testRequest, testUser);
});
// 检查是否是 InvocationTargetException 包装的 BusinessException
assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
Throwable cause = exception.getCause();
assertTrue(cause instanceof BusinessException);
assertTrue(cause.getMessage().contains("购买数量超过限制"));
}
@Test
void testValidateOrderRequest_PriceCalculation() {
// 设置多个商品项
OrderCreateRequest.OrderGoodsItem goodsItem1 = new OrderCreateRequest.OrderGoodsItem();
goodsItem1.setGoodsId(10018);
goodsItem1.setQuantity(2);
OrderCreateRequest.OrderGoodsItem goodsItem2 = new OrderCreateRequest.OrderGoodsItem();
goodsItem2.setGoodsId(10019);
goodsItem2.setQuantity(1);
testRequest.setGoodsItems(Arrays.asList(goodsItem1, goodsItem2));
testRequest.setTotalPrice(new BigDecimal("297.00")); // 99*2 + 99*1
// 准备第二个商品
ShopGoods testGoods2 = new ShopGoods();
testGoods2.setGoodsId(10019);
testGoods2.setName("测试商品2");
testGoods2.setPrice(new BigDecimal("99.00"));
testGoods2.setStatus(0);
testGoods2.setStock(100);
when(shopGoodsService.getById(10018)).thenReturn(testGoods);
when(shopGoodsService.getById(10019)).thenReturn(testGoods2);
when(orderConfig.getTenantRule(1)).thenReturn(null);
// 执行验证 - 应该成功
assertDoesNotThrow(() -> {
java.lang.reflect.Method method = OrderBusinessService.class
.getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
method.setAccessible(true);
method.invoke(orderBusinessService, testRequest, testUser);
});
// 验证总金额计算正确
assertEquals(new BigDecimal("297.00"), testRequest.getTotalPrice());
}
@Test
void testValidateOrderRequest_PriceDiscrepancy() {
// 设置前端传入的金额与后台计算不一致
testRequest.setTotalPrice(new BigDecimal("88.00")); // 错误的金额
when(shopGoodsService.getById(10018)).thenReturn(testGoods);
// 执行验证 - 应该抛出异常
Exception exception = assertThrows(Exception.class, () -> {
java.lang.reflect.Method method = OrderBusinessService.class
.getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
method.setAccessible(true);
method.invoke(orderBusinessService, testRequest, testUser);
});
// 检查是否是 InvocationTargetException 包装的 BusinessException
assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
Throwable cause = exception.getCause();
assertTrue(cause instanceof BusinessException);
assertTrue(cause.getMessage().contains("订单金额计算错误"));
}
}