修复下单接口

This commit is contained in:
2025-08-09 14:43:47 +08:00
parent 1bda2263c0
commit eb1f5efc10
6 changed files with 706 additions and 25 deletions

View File

@@ -100,17 +100,22 @@ public class ShopOrderController extends BaseController {
@Operation(summary = "添加订单")
@PostMapping()
public ApiResult<?> save(@Valid @RequestBody OrderCreateRequest request) {
public ApiResult<?> save(@RequestBody OrderCreateRequest request) {
User loginUser = getLoginUser();
if (loginUser == null) {
return fail("用户未登录");
}
try {
// 记录请求信息用于调试
logger.info("收到下单请求 - 用户ID{}商品ID{},数量:{},总价:{}租户ID{}",
loginUser.getUserId(), request.getActualFormId(), request.getActualTotalNum(),
request.getTotalPrice(), request.getTenantId());
Map<String, String> wxOrderInfo = orderBusinessService.createOrder(request, loginUser);
return success("下单成功", wxOrderInfo);
} catch (Exception e) {
logger.error("创建订单失败", e);
logger.error("创建订单失败 - 用户ID{},请求:{}", loginUser.getUserId(), request, e);
return fail(e.getMessage());
}
}

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 com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.List;
/**
* 订单创建请求DTO
@@ -104,6 +105,18 @@ public class OrderCreateRequest {
@Schema(description = "来源ID存商品ID")
private Integer formId;
@Schema(description = "商品ID兼容字段")
@JsonProperty("goodsId")
private Integer goodsId;
@Schema(description = "购买数量(兼容字段)")
@JsonProperty("quantity")
private Integer quantity;
@Schema(description = "商品项目列表(支持多商品下单)")
@JsonProperty("goodsItems")
private List<GoodsItem> goodsItems;
@Schema(description = "支付类型0余额支付, 1微信支付102微信Native2会员卡支付3支付宝4现金5POS机6VIP月卡7VIP年卡8VIP次卡9IC月卡10IC年卡11IC次卡12免费13VIP充值卡14IC充值卡15积分支付16VIP季卡17IC季卡18代付")
private Integer payType;
@@ -129,4 +142,55 @@ public class OrderCreateRequest {
@Schema(description = "租户id")
@NotNull(message = "租户ID不能为空")
private Integer tenantId;
/**
* 商品项目内部类
*/
@Data
@Schema(name = "GoodsItem", description = "商品项目")
public static class GoodsItem {
@Schema(description = "商品ID")
@JsonProperty("goodsId")
private Integer goodsId;
@Schema(description = "购买数量")
@JsonProperty("quantity")
private Integer quantity;
@Schema(description = "商品价格")
@JsonProperty("price")
private BigDecimal price;
}
/**
* 获取实际的商品ID兼容多种字段名
*/
public Integer getActualFormId() {
if (formId != null) {
return formId;
}
if (goodsId != null) {
return goodsId;
}
if (goodsItems != null && !goodsItems.isEmpty()) {
return goodsItems.get(0).getGoodsId();
}
return null;
}
/**
* 获取实际的购买数量(兼容多种字段名)
*/
public Integer getActualTotalNum() {
if (totalNum != null) {
return totalNum;
}
if (quantity != null) {
return quantity;
}
if (goodsItems != null && !goodsItems.isEmpty()) {
return goodsItems.get(0).getQuantity();
}
return 1; // 默认数量为1
}
}

View File

@@ -6,6 +6,7 @@ import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.config.OrderConfigProperties;
import com.gxwebsoft.shop.dto.OrderCreateRequest;
import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.shop.entity.ShopGoods;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@@ -29,6 +30,9 @@ public class OrderBusinessService {
@Resource
private ShopOrderService shopOrderService;
@Resource
private ShopGoodsService shopGoodsService;
@Resource
private OrderConfigProperties orderConfig;
@@ -44,19 +48,22 @@ public class OrderBusinessService {
// 1. 参数校验
validateOrderRequest(request, loginUser);
// 2. 构建订单对象
ShopOrder shopOrder = buildShopOrder(request, loginUser);
// 2. 验证商品信息(从数据库查询)
ShopGoods goods = validateAndGetGoods(request);
// 3. 应用业务规则
// 3. 构建订单对象
ShopOrder shopOrder = buildShopOrder(request, loginUser, goods);
// 4. 应用业务规则
applyBusinessRules(shopOrder, loginUser);
// 4. 保存订单
// 5. 保存订单
boolean saved = shopOrderService.save(shopOrder);
if (!saved) {
throw new BusinessException("订单保存失败");
}
// 5. 创建微信支付订单
// 6. 创建微信支付订单
try {
return shopOrderService.createWxOrder(shopOrder);
} catch (Exception e) {
@@ -73,28 +80,121 @@ public class OrderBusinessService {
throw new BusinessException("用户未登录");
}
if (request.getTotalPrice() == null || request.getTotalPrice().compareTo(BigDecimal.ZERO) <= 0) {
// 检查必填字段
if (request.getActualFormId() == null) {
throw new BusinessException("商品ID不能为空");
}
if (request.getActualTotalNum() == null || request.getActualTotalNum() <= 0) {
throw new BusinessException("购买数量必须大于0");
}
// 如果没有传递总价,先跳过验证,后续会根据商品信息计算
if (request.getTotalPrice() != null && request.getTotalPrice().compareTo(BigDecimal.ZERO) <= 0) {
throw new BusinessException("商品金额不能为0");
}
// 检查租户ID
if (request.getTenantId() == null) {
request.setTenantId(loginUser.getTenantId());
}
// 检查订单类型
if (request.getType() == null) {
// 设置默认订单类型为商城订单
request.setType(0);
}
// 检查租户特殊规则
OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(request.getTenantId());
if (tenantRule != null && tenantRule.getMinAmount() != null) {
if (request.getTotalPrice().compareTo(tenantRule.getMinAmount()) < 0) {
throw new BusinessException(tenantRule.getMinAmountMessage());
if (orderConfig != null && request.getTotalPrice() != null) {
OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(request.getTenantId());
if (tenantRule != null && tenantRule.getMinAmount() != null) {
if (request.getTotalPrice().compareTo(tenantRule.getMinAmount()) < 0) {
throw new BusinessException(tenantRule.getMinAmountMessage());
}
}
}
}
/**
* 验证商品信息并获取商品详情
*/
private ShopGoods validateAndGetGoods(OrderCreateRequest request) {
Integer goodsId = request.getActualFormId();
if (goodsId == null) {
throw new BusinessException("商品ID不能为空");
}
// 从数据库查询商品信息
ShopGoods goods = shopGoodsService.getById(goodsId);
if (goods == null) {
throw new BusinessException("商品不存在商品ID" + goodsId);
}
// 验证商品状态
if (goods.getDeleted() != null && goods.getDeleted() == 1) {
throw new BusinessException("商品已删除");
}
if (goods.getStatus() != 0) {
throw new BusinessException("商品未上架");
}
// 验证库存
Integer totalNum = request.getActualTotalNum();
if (goods.getStock() != null && totalNum != null) {
if (goods.getStock() < totalNum) {
throw new BusinessException("商品库存不足,当前库存:" + goods.getStock());
}
}
// 验证价格允许一定的误差比如0.01元)
if (goods.getPrice() != null && request.getTotalPrice() != null && totalNum != null) {
BigDecimal expectedTotal = goods.getPrice().multiply(new BigDecimal(totalNum));
BigDecimal priceDiff = request.getTotalPrice().subtract(expectedTotal).abs();
if (priceDiff.compareTo(new BigDecimal("0.01")) > 0) {
throw new BusinessException("商品价格异常,数据库价格:" + goods.getPrice() +
",期望总价:" + expectedTotal + ",请求价格:" + request.getTotalPrice());
}
}
log.info("商品验证通过 - 商品ID{},商品名称:{},价格:{},库存:{},购买数量:{}",
goods.getGoodsId(), goods.getName(), goods.getPrice(), goods.getStock(), totalNum);
return goods;
}
/**
* 构建订单对象
*/
private ShopOrder buildShopOrder(OrderCreateRequest request, User loginUser) {
private ShopOrder buildShopOrder(OrderCreateRequest request, User loginUser, ShopGoods goods) {
ShopOrder shopOrder = new ShopOrder();
// 复制请求参数到订单对象
BeanUtils.copyProperties(request, shopOrder);
// 设置兼容字段
Integer actualFormId = request.getActualFormId();
Integer actualTotalNum = request.getActualTotalNum();
if (actualFormId != null) {
shopOrder.setFormId(actualFormId);
}
if (actualTotalNum != null) {
shopOrder.setTotalNum(actualTotalNum);
}
// 使用数据库中的商品信息覆盖价格(确保价格准确性)
if (goods.getPrice() != null && actualTotalNum != null) {
BigDecimal totalPrice = goods.getPrice().multiply(new BigDecimal(actualTotalNum));
shopOrder.setTotalPrice(totalPrice);
shopOrder.setPrice(totalPrice);
// 如果没有设置实际付款金额,则使用总价
if (shopOrder.getPayPrice() == null) {
shopOrder.setPayPrice(totalPrice);
}
}
// 设置用户相关信息
shopOrder.setUserId(loginUser.getUserId());
shopOrder.setOpenid(loginUser.getOpenid());
@@ -107,12 +207,19 @@ public class OrderBusinessService {
// 设置默认备注
if (shopOrder.getComments() == null) {
shopOrder.setComments(orderConfig.getDefaultConfig().getDefaultComments());
if (orderConfig != null && orderConfig.getDefaultConfig() != null) {
shopOrder.setComments(orderConfig.getDefaultConfig().getDefaultComments());
} else {
shopOrder.setComments("暂无");
}
}
// 设置默认支付状态
shopOrder.setPayStatus(false);
log.info("构建订单完成 - 订单号:{}商品ID{},数量:{},总价:{}",
shopOrder.getOrderNo(), actualFormId, actualTotalNum, shopOrder.getTotalPrice());
return shopOrder;
}
@@ -121,11 +228,13 @@ public class OrderBusinessService {
*/
private void applyBusinessRules(ShopOrder shopOrder, User loginUser) {
// 测试账号处理
if (orderConfig.isTestAccount(loginUser.getPhone())) {
BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount();
shopOrder.setPrice(testAmount);
shopOrder.setTotalPrice(testAmount);
log.info("应用测试账号规则,用户:{},测试金额:{}", loginUser.getPhone(), testAmount);
if (orderConfig != null && orderConfig.isTestAccount(loginUser.getPhone())) {
if (orderConfig.getTestAccount() != null) {
BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount();
shopOrder.setPrice(testAmount);
shopOrder.setTotalPrice(testAmount);
log.info("应用测试账号规则,用户:{},测试金额:{}", loginUser.getPhone(), testAmount);
}
}
// 其他业务规则可以在这里添加
@@ -140,10 +249,12 @@ public class OrderBusinessService {
throw new BusinessException("订单金额必须大于0");
}
OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(tenantId);
if (tenantRule != null && tenantRule.getMinAmount() != null) {
if (amount.compareTo(tenantRule.getMinAmount()) < 0) {
throw new BusinessException(tenantRule.getMinAmountMessage());
if (orderConfig != null) {
OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(tenantId);
if (tenantRule != null && tenantRule.getMinAmount() != null) {
if (amount.compareTo(tenantRule.getMinAmount()) < 0) {
throw new BusinessException(tenantRule.getMinAmountMessage());
}
}
}
}
@@ -152,6 +263,6 @@ public class OrderBusinessService {
* 检查是否为测试账号
*/
public boolean isTestAccount(String phone) {
return orderConfig.isTestAccount(phone);
return orderConfig != null && orderConfig.isTestAccount(phone);
}
}