|
|
@@ -0,0 +1,370 @@
|
|
|
+package org.dromara.order.controller.mini;
|
|
|
+
|
|
|
+import jakarta.validation.constraints.NotNull;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
+import org.dromara.common.core.domain.R;
|
|
|
+import org.dromara.common.core.enums.OrderSourceEnum;
|
|
|
+import org.dromara.common.core.enums.OrderStatus;
|
|
|
+import org.dromara.common.core.enums.SysPlatformYesNo;
|
|
|
+import org.dromara.common.log.annotation.Log;
|
|
|
+import org.dromara.common.log.enums.BusinessType;
|
|
|
+import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
+import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
+import org.dromara.common.satoken.utils.LoginHelper;
|
|
|
+import org.dromara.common.web.core.BaseController;
|
|
|
+import org.dromara.customer.api.RemoteCustomerContactService;
|
|
|
+import org.dromara.customer.api.RemoteCustomerService;
|
|
|
+import org.dromara.customer.api.domain.CustomerApiVo;
|
|
|
+import org.dromara.order.domain.bo.OrderMainBo;
|
|
|
+import org.dromara.order.domain.bo.OrderProductBo;
|
|
|
+import org.dromara.order.domain.bo.PcSubmitOrderBo;
|
|
|
+import org.dromara.order.domain.dto.OrderPayDto;
|
|
|
+import org.dromara.order.domain.vo.OrderMainVo;
|
|
|
+import org.dromara.order.domain.vo.OrderProductVo;
|
|
|
+import org.dromara.order.service.IOrderCustomerFlowLinkService;
|
|
|
+import org.dromara.order.service.IOrderCustomerFlowNodeLinkService;
|
|
|
+import org.dromara.order.service.IOrderCustomerFlowService;
|
|
|
+import org.dromara.order.service.IOrderMainService;
|
|
|
+import org.dromara.product.api.RemoteProductService;
|
|
|
+import org.dromara.product.api.RemoteProductShoppingCartService;
|
|
|
+import org.dromara.product.api.domain.ProductVo;
|
|
|
+import org.dromara.product.api.domain.RemoteProductShoppingCartVo;
|
|
|
+import org.dromara.system.api.RemoteUserService;
|
|
|
+import org.springframework.validation.annotation.Validated;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+import static org.dromara.common.mybatis.core.mapper.BaseMapperPlus.log;
|
|
|
+
|
|
|
+@Validated
|
|
|
+@RequiredArgsConstructor
|
|
|
+@RestController
|
|
|
+@RequestMapping("/miniOrder")
|
|
|
+public class MiniOrderController extends BaseController {
|
|
|
+
|
|
|
+
|
|
|
+ @DubboReference
|
|
|
+ private RemoteUserService remoteUserService;
|
|
|
+
|
|
|
+ @DubboReference
|
|
|
+ private RemoteCustomerService remoteCustomerService;
|
|
|
+
|
|
|
+ @DubboReference
|
|
|
+ private RemoteProductService remoteProductService;
|
|
|
+
|
|
|
+ @DubboReference
|
|
|
+ private RemoteCustomerContactService remoteCustomerContactService;
|
|
|
+
|
|
|
+ @DubboReference
|
|
|
+ private RemoteProductShoppingCartService remoteProductShoppingCartService;
|
|
|
+
|
|
|
+ //客户订单流程
|
|
|
+ private final IOrderCustomerFlowService orderCustomerFlowService;
|
|
|
+
|
|
|
+ private final IOrderCustomerFlowLinkService orderCustomerFlowLinkService;
|
|
|
+
|
|
|
+ private final IOrderMainService orderMainService;
|
|
|
+
|
|
|
+
|
|
|
+ private final IOrderCustomerFlowNodeLinkService orderCustomerFlowNodeLinkService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询订单列表
|
|
|
+ * 小程序用户只能查询自己的订单
|
|
|
+ */
|
|
|
+ @GetMapping("/list")
|
|
|
+ public TableDataInfo<OrderMainVo> list(OrderMainBo bo, PageQuery pageQuery) {
|
|
|
+ // 获取当前登录用户的企业ID
|
|
|
+ Long customerId = LoginHelper.getLoginUser().getCustomerId();
|
|
|
+
|
|
|
+ Long userId = LoginHelper.getLoginUser().getUserId();
|
|
|
+ // 强制设置企业ID,防止越权访问
|
|
|
+ bo.setCustomerId(customerId);
|
|
|
+ bo.setUserId(userId);
|
|
|
+ bo.setIsSplitChild(SysPlatformYesNo.NO.getCode());
|
|
|
+ return orderMainService.queryPageList(bo, pageQuery);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取订单详细信息
|
|
|
+ * 小程序用户只能查询自己的订单
|
|
|
+ *
|
|
|
+ * @param id 订单主键
|
|
|
+ */
|
|
|
+ @GetMapping("/{id}")
|
|
|
+ public R<OrderMainVo> getInfo(@NotNull(message = "主键不能为空")
|
|
|
+ @PathVariable("id") Long id) {
|
|
|
+ // 查询订单信息
|
|
|
+ OrderMainVo vo = orderMainService.queryById(id);
|
|
|
+
|
|
|
+ // 验证订单是否属于当前用户的小程序用户
|
|
|
+ if (vo != null) {
|
|
|
+ Long customerId = LoginHelper.getLoginUser().getCustomerId();
|
|
|
+ Long userId = LoginHelper.getLoginUser().getUserId();
|
|
|
+ if (!userId.equals(vo.getUserId())) {
|
|
|
+ return R.fail("无权访问该订单");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.ok(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据订单ID查询订单商品明细
|
|
|
+ * MINI端用户只能查询自己的订单商品
|
|
|
+ *
|
|
|
+ * @param orderIds 订单ID列表
|
|
|
+ */
|
|
|
+ @GetMapping("/products")
|
|
|
+ public TableDataInfo<OrderProductVo> getOrderProducts(@RequestParam("orderIds") List<Long> orderIds) {
|
|
|
+ if (orderIds == null || orderIds.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("订单ID列表不能为空");
|
|
|
+ }
|
|
|
+ if (orderIds.size() > 1000) {
|
|
|
+ throw new IllegalArgumentException("订单ID数量不能超过1000个");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前登录用户的企业ID
|
|
|
+ Long customerId = LoginHelper.getLoginUser().getCustomerId();
|
|
|
+
|
|
|
+ // 强制设置企业ID,防止越权访问
|
|
|
+ Long userId = LoginHelper.getLoginUser().getUserId();
|
|
|
+
|
|
|
+ // 验证所有订单是否都属于当前用户的企业
|
|
|
+ for (Long orderId : orderIds) {
|
|
|
+ OrderMainVo order = orderMainService.queryById(orderId);
|
|
|
+ if (order == null) {
|
|
|
+ throw new IllegalArgumentException("订单ID " + orderId + " 不存在");
|
|
|
+ }
|
|
|
+ if (!userId.equals(order.getUserId())) {
|
|
|
+ throw new IllegalArgumentException("无权访问订单ID " + orderId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<Long> uniqueOrderIds = new HashSet<>(orderIds);
|
|
|
+ return orderMainService.getCustomerOrderProductList(uniqueOrderIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取消订单
|
|
|
+ * MINI端用户只能取消自己的订单
|
|
|
+ *
|
|
|
+ * @param bo 订单业务对象
|
|
|
+ */
|
|
|
+ @Log(title = "MINI端-订单管理", businessType = BusinessType.UPDATE)
|
|
|
+ @PutMapping("/cancel")
|
|
|
+ public R<Void> cancelOrder(@RequestBody OrderMainBo bo) {
|
|
|
+ // 获取当前登录用户的企业ID
|
|
|
+ Long customerId = LoginHelper.getLoginUser().getCustomerId();
|
|
|
+ // 获取当前登录用户ID
|
|
|
+ Long userId = LoginHelper.getLoginUser().getUserId();
|
|
|
+
|
|
|
+ // 验证订单是否属于当前用户的企业
|
|
|
+ OrderMainVo existingOrder = orderMainService.queryById(bo.getId());
|
|
|
+ if (existingOrder == null) {
|
|
|
+ return R.fail("订单不存在");
|
|
|
+ }
|
|
|
+ if (!userId.equals(existingOrder.getUserId())) {
|
|
|
+ return R.fail("无权取消该订单");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 强制设置企业ID
|
|
|
+ bo.setCustomerId(customerId);
|
|
|
+ bo.setOrderStatuses(OrderStatus.CANCEL.getCode());
|
|
|
+
|
|
|
+ return toAjax(orderMainService.updateStatus(bo));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 提交订单(MINI端下单)
|
|
|
+ * 调用服务层 insertByBo 方法实现
|
|
|
+ */
|
|
|
+ @Log(title = "MINI端-提交订单", businessType = BusinessType.INSERT)
|
|
|
+ @PostMapping("/submit")
|
|
|
+ public R<Long> submitOrder(@RequestBody @Validated PcSubmitOrderBo bo) {
|
|
|
+ try {
|
|
|
+ // 获取当前登录用户的企业ID
|
|
|
+ Long userId = LoginHelper.getLoginUser().getUserId();
|
|
|
+
|
|
|
+ Long customerId = LoginHelper.getLoginUser().getCustomerId();
|
|
|
+ Map<Long, CustomerApiVo> longCustomerApiVoMap = remoteCustomerService.selectCustomerByIds(Set.of(customerId));
|
|
|
+ CustomerApiVo customerApiVo = longCustomerApiVoMap.get(customerId);
|
|
|
+
|
|
|
+ // 构造 OrderMainBo 对象
|
|
|
+ OrderMainBo mainBo = new OrderMainBo();
|
|
|
+ mainBo.setCustomerId(customerId);
|
|
|
+ mainBo.setUserId(userId);
|
|
|
+ mainBo.setShippingAddressId(bo.getShippingAddressId());
|
|
|
+ mainBo.setPurchaseReason(bo.getPurchaseReason());
|
|
|
+ mainBo.setRemark(bo.getRemark());
|
|
|
+ mainBo.setExpenseType(bo.getExpenseType());
|
|
|
+ mainBo.setShippingFee(bo.getShippingFee());
|
|
|
+
|
|
|
+ if (null != customerApiVo) {
|
|
|
+ mainBo.setCompanyId(customerApiVo.getCompanyId());
|
|
|
+ mainBo.setCustomerCode(customerApiVo.getCustomerNo());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析配送时间
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+ LocalDate deliveryLocalDate = LocalDate.parse(bo.getDeliveryDate(), formatter);
|
|
|
+ Date expectedDeliveryTime = Date.from(deliveryLocalDate.atStartOfDay().toInstant(java.time.ZoneOffset.UTC));
|
|
|
+ mainBo.setExpectedDeliveryTime(expectedDeliveryTime);
|
|
|
+
|
|
|
+ // 设置仓库(假设默认仓库)
|
|
|
+ mainBo.setWarehouseId(1L); // TODO: 后续可配置或根据客户动态获取
|
|
|
+
|
|
|
+
|
|
|
+ // 设置订单状态为待支付
|
|
|
+ mainBo.setOrderStatus(OrderStatus.PENDING_PAYMENT.getCode());
|
|
|
+
|
|
|
+ // 设置审核状态为待审核
|
|
|
+ mainBo.setCheckStatus("0");
|
|
|
+
|
|
|
+ //商城下单默认需要审核--如果设置审批流则不需要
|
|
|
+ mainBo.setIsNeedCheck(SysPlatformYesNo.YES.getCode());
|
|
|
+
|
|
|
+ mainBo.setOrderSource(OrderSourceEnum.BEFORE_ADD.getCode());
|
|
|
+
|
|
|
+ // 设置订单商品列表
|
|
|
+ // mainBo.setOrderProductBos(bo.getOrderProductBos());
|
|
|
+ Map<Long, Long> productNumMap;
|
|
|
+ // 1. 获取购物车项
|
|
|
+ if (bo.getPlaceOrderType() == 1) {
|
|
|
+ Set<Long> productShoppingCartIds = bo.getProductShoppingCartId();
|
|
|
+ if (productShoppingCartIds == null || productShoppingCartIds.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("购物车项ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ List<RemoteProductShoppingCartVo> shoppingCartList = remoteProductShoppingCartService.getShoppingCartList(productShoppingCartIds);
|
|
|
+ if (shoppingCartList.isEmpty()) {
|
|
|
+ throw new IllegalStateException("购物车数据不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 构建 productId -> productNum 映射(防御性:过滤 null key)
|
|
|
+ productNumMap = shoppingCartList.stream()
|
|
|
+ .filter(item -> item.getProductId() != null && item.getProductNum() != null)
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ RemoteProductShoppingCartVo::getProductId,
|
|
|
+ RemoteProductShoppingCartVo::getProductNum,
|
|
|
+ (existing, replacement) -> existing // 防止重复 key 冲突(理论上不应发生)
|
|
|
+ ));
|
|
|
+ } else {
|
|
|
+ productNumMap = bo.getProductInfo().stream()
|
|
|
+ .filter(item -> item.getProductId() != null && item.getProductNum() != null)
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ PcSubmitOrderBo.PcOrderProduct::getProductId,
|
|
|
+ PcSubmitOrderBo.PcOrderProduct::getProductNum,
|
|
|
+ (existing, replacement) -> existing // 防止重复 key 冲突(理论上不应发生)
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 3. 提取所有商品 ID(使用 List/Collection,而非拼接字符串!)
|
|
|
+ List<Long> productIds = new ArrayList<>(productNumMap.keySet());
|
|
|
+
|
|
|
+
|
|
|
+ // 如果远程服务只接受字符串
|
|
|
+ List<ProductVo> productDetails = remoteProductService.getProductDetails(productIds);
|
|
|
+
|
|
|
+ // 4. 构建订单商品列表
|
|
|
+ List<OrderProductBo> orderProductBos = productDetails.stream()
|
|
|
+ .map(productVo -> {
|
|
|
+ Long productId = productVo.getId();
|
|
|
+ Long quantity = productNumMap.get(productId);
|
|
|
+ if (quantity == null) {
|
|
|
+ // 理论上不会发生,但防御性处理
|
|
|
+ log.warn("商品 {} 在购物车中无数量信息,跳过");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ OrderProductBo orderProductBo = new OrderProductBo();
|
|
|
+ orderProductBo.setProductId(productId);
|
|
|
+ orderProductBo.setProductNo(productVo.getProductNo());
|
|
|
+ orderProductBo.setProductName(productVo.getItemName());
|
|
|
+ orderProductBo.setProductUnitId(Long.valueOf(productVo.getUnitId()));
|
|
|
+ orderProductBo.setProductUnit(productVo.getUnitName());
|
|
|
+ orderProductBo.setProductImage(productVo.getProductImage());
|
|
|
+ orderProductBo.setOrderPrice(productVo.getMemberPrice());
|
|
|
+ orderProductBo.setMarketPrice(productVo.getMarketPrice());
|
|
|
+ orderProductBo.setTaxRate(productVo.getTaxRate());
|
|
|
+ orderProductBo.setCategoryName(productVo.getCategoryName());
|
|
|
+ orderProductBo.setPurchasingPrice(productVo.getPurchasingPrice());
|
|
|
+ orderProductBo.setMinOrderQuantity(productVo.getMinOrderQuantity());
|
|
|
+ orderProductBo.setMinSellingPrice(productVo.getMinSellingPrice());
|
|
|
+ orderProductBo.setOrderQuantity(quantity);
|
|
|
+ orderProductBo.setSubtotal(productVo.getMemberPrice().multiply(BigDecimal.valueOf(quantity)));
|
|
|
+ return orderProductBo;
|
|
|
+ })
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (orderProductBos.isEmpty()) {
|
|
|
+ throw new IllegalStateException("无可下单的商品");
|
|
|
+ }
|
|
|
+
|
|
|
+ mainBo.setOrderProductBos(orderProductBos);
|
|
|
+
|
|
|
+ // 5. 保存订单(关键:成功后再删除购物车)
|
|
|
+ Long orderId = orderMainService.insertOrder(bo, mainBo);
|
|
|
+
|
|
|
+ return R.ok(orderId); // 正确返回 ID
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("小程序端提交订单失败", e);
|
|
|
+ return R.fail("下单失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 订单支付(MINI端下单)
|
|
|
+ */
|
|
|
+ @Log(title = "MINI端-订单支付", businessType = BusinessType.UPDATE)
|
|
|
+ @PostMapping("/orderPay")
|
|
|
+ public R<?> orderPay(@RequestBody @Validated OrderPayDto payDto) {
|
|
|
+ Long customerId = LoginHelper.getLoginUser().getCustomerId();
|
|
|
+
|
|
|
+ // 调用 Service,返回支付结果
|
|
|
+ Boolean orderPayResult = orderMainService.orderPay(
|
|
|
+ customerId,
|
|
|
+ payDto.getOrderId(),
|
|
|
+ payDto.getPayType()
|
|
|
+ );
|
|
|
+
|
|
|
+ return R.ok(orderPayResult);
|
|
|
+ }
|
|
|
+
|
|
|
+ @GetMapping("/batchConfirmation")
|
|
|
+ public R<Void> batchConfirmation(@RequestParam("orderIds") List<Long> orderIds) {
|
|
|
+ if (orderIds == null || orderIds.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("订单ID列表不能为空");
|
|
|
+ }
|
|
|
+ if (orderIds.size() > 1000) {
|
|
|
+ throw new IllegalArgumentException("订单ID数量不能超过1000个");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前登录用户的企业ID
|
|
|
+ Long customerId = LoginHelper.getLoginUser().getCustomerId();
|
|
|
+ // 获取当前登录用户的用户ID
|
|
|
+ Long userId = LoginHelper.getLoginUser().getUserId();
|
|
|
+
|
|
|
+ // 验证所有订单是否都属于当前用户的企业
|
|
|
+ for (Long orderId : orderIds) {
|
|
|
+ OrderMainVo order = orderMainService.queryById(orderId);
|
|
|
+ if (order == null) {
|
|
|
+ throw new IllegalArgumentException("订单ID " + orderId + " 不存在");
|
|
|
+ }
|
|
|
+ if (!userId.equals(order.getUserId())) {
|
|
|
+ throw new IllegalArgumentException("无权访问订单ID " + orderId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<Long> uniqueOrderIds = new HashSet<>(orderIds);
|
|
|
+ return toAjax(orderMainService.batchConfirmation(uniqueOrderIds));
|
|
|
+ }
|
|
|
+}
|