瀏覽代碼

add recycle

Mr.qian 1 月之前
父節點
當前提交
328a57cf4a

+ 138 - 70
mall-service/src/main/java/com/txz/mall/controller/appcontroller/AppOrderController.java

@@ -7,12 +7,16 @@ import com.txz.mall.business.OrderServiceBusiness;
 import com.txz.mall.core.AuthService;
 import com.txz.mall.core.Result;
 import com.txz.mall.core.ResultCode;
+import com.txz.mall.core.ServiceException;
 import com.txz.mall.dao.StoreOrderMapper;
 import com.txz.mall.dubbo.client.CifUserDubboServiceClient;
+import com.txz.mall.dubbo.client.OperatingConfigDubboServiceClient;
 import com.txz.mall.model.StoreOrder;
 import com.txz.mall.service.StoreOrderService;
 import com.txz.mall.util.EasyToUseUtil;
+import com.txz.mall.util.I18nUtil;
 import com.txz.mall.web.param.updateparam.StoreOrderUpdateParam;
+import com.txz.mall.web.ro.RecycleOrderRO;
 import dto.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -27,6 +31,8 @@ import vo.StoreOrderCountItemVO;
 import vo.StoreOrderVO;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.Date;
 import java.util.List;
 
@@ -37,38 +43,43 @@ import java.util.List;
 @RestController
 @RequestMapping("/app/order")
 public class AppOrderController {
-
+    
     private static Logger log = LoggerFactory.getLogger(AppOrderController.class);
-
+    
     @Resource
     private StoreOrderService storeOrderService;
+    
     @Resource
     private OrderServiceBusiness orderServiceBusiness;
-
+    
+    @Resource
+    private OperatingConfigDubboServiceClient configDubboServiceClient;
+    
     @Resource
     private CifUserDubboServiceClient userDubboServiceClient;
-
+    
     @PostMapping("/add")
     @ApiOperation(value = "创建订单")
     public Result add(@Validated @RequestBody CreateOrderRequest orderRequest) {
-
-
+        
+        
         if (orderRequest == null) {
             return Result.fail(ResultCode.OBJECT_IS_NULL);
         }
         Long tokenUserId = AuthService.getTokenUserId(null);
-//        UserDTO user = userDubboServiceClient.getUser(tokenUserId);
-//        if (user.getHasOrder() != 1) {
-//            return Result.fail(ResultCode.USER_STATUS_IS_ERROR);
-//        }
-
+        //        UserDTO user = userDubboServiceClient.getUser(tokenUserId);
+        //        if (user.getHasOrder() != 1) {
+        //            return Result.fail(ResultCode.USER_STATUS_IS_ERROR);
+        //        }
+        
         orderRequest.setUserId(tokenUserId);
         MyRecord record = storeOrderService.createOrder(orderRequest);
         return Result.success(record);
     }
-
+    
     @Resource
     private StoreOrderMapper storeOrderMapper;
+    
     @DeleteMapping("/delete")
     @ApiOperation(value = "订单删除")
     public Result delete(@RequestParam("orderNo") String orderNo) {
@@ -77,52 +88,52 @@ public class AppOrderController {
         }
         try {
             StoreOrder storeOrder = new StoreOrder();
-           // storeOrder.setId(id);
+            // storeOrder.setId(id);
             storeOrder.setIsDelete(1);
-
+            
             Condition condition = new Condition(StoreOrder.class);
-            condition.createCriteria().andEqualTo("orderId",orderNo);
-
-            storeOrderMapper.updateByConditionSelective(storeOrder,condition);
+            condition.createCriteria().andEqualTo("orderId", orderNo);
+            
+            storeOrderMapper.updateByConditionSelective(storeOrder, condition);
         } catch (Exception e) {
             log.error("删除对象操作异常e:{}", e);
             return Result.fail(ResultCode.INTERNAL_SERVER_ERROR);
         }
         return Result.success();
     }
-
-
-    //这个接口太危险了理论上不会有这种需求先注释掉再说
-//    @PutMapping("/update")
-//    @ApiOperation(value = "订单更新")
-//    public Result update(@RequestBody StoreOrder storeOrder) {
-//        if (storeOrder == null) {
-//            return Result.fail(ResultCode.OBJECT_IS_NULL);
-//        }
-//        if (storeOrder.getId() == null) {
-//            return Result.fail(ResultCode.ID_IS_NULL);
-//        }
-//        try {
-//            storeOrder.setUpdateTime(new Date());
-//            //    		storeOrder.setUpdateUserId(userId);
-//            storeOrderService.update(storeOrder);
-//        } catch (Exception e) {
-//            log.error("更新对象操作异常e:{}", e);
-//            return Result.fail(ResultCode.INTERNAL_SERVER_ERROR);
-//        }
-//        return Result.success();
-//    }
-//
+    
+    
+    // 这个接口太危险了理论上不会有这种需求先注释掉再说
+    //    @PutMapping("/update")
+    //    @ApiOperation(value = "订单更新")
+    //    public Result update(@RequestBody StoreOrder storeOrder) {
+    //        if (storeOrder == null) {
+    //            return Result.fail(ResultCode.OBJECT_IS_NULL);
+    //        }
+    //        if (storeOrder.getId() == null) {
+    //            return Result.fail(ResultCode.ID_IS_NULL);
+    //        }
+    //        try {
+    //            storeOrder.setUpdateTime(new Date());
+    //            //    		storeOrder.setUpdateUserId(userId);
+    //            storeOrderService.update(storeOrder);
+    //        } catch (Exception e) {
+    //            log.error("更新对象操作异常e:{}", e);
+    //            return Result.fail(ResultCode.INTERNAL_SERVER_ERROR);
+    //        }
+    //        return Result.success();
+    //    }
+    //
     @PutMapping("/binding/address")
     @ApiOperation(value = "订单绑定地址")
     public Result update(@RequestBody StoreOrderUpdateParam storeOrderUpdateParam) {
-
+        
         try {
             StoreOrder storeOrder = new StoreOrder();
             storeOrder.setOrderId(storeOrderUpdateParam.getOrderId());
             storeOrder.setAddressId(storeOrderUpdateParam.getAddressId());
             EasyToUseUtil.appUpdateAssignment(new Date(), storeOrder);
-
+            
             storeOrderService.bindingAddress(storeOrder);
         } catch (Exception e) {
             log.error("更新对象操作异常e:{}", e);
@@ -130,8 +141,8 @@ public class AppOrderController {
         }
         return Result.success();
     }
-
-
+    
+    
     //    @GetMapping("/detail")
     //    @ApiOperation(value = "订单获取详情")
     //    public Result<StoreOrderVO> detail(@RequestParam Long id) {
@@ -141,20 +152,20 @@ public class AppOrderController {
     //        StoreOrderVO vo = orderServiceBusiness.orderDetail(id,null);
     //        return Result.success(vo);
     //    }
-
+    
     @GetMapping("/detail")
     @ApiOperation(value = "订单获取详情")
     public Result<StoreOrderVO> detail(@RequestParam(value = "id", required = false) Long id
             , @RequestParam(value = "orderNo", required = false) String orderNo) {
-
+        
         if (ObjectUtils.isEmpty(orderNo)) {
             return Result.fail(ResultCode.CODE_IS_NULL);
         }
         StoreOrderVO vo = orderServiceBusiness.orderDetail(id, orderNo);
         return Result.success(vo);
     }
-
-
+    
+    
     @PostMapping("/list")
     @ApiOperation(value = "订单获取列表")
     public Result<List<StoreOrderVO>> list(@RequestBody StoreOrderDTO dto) {
@@ -165,11 +176,11 @@ public class AppOrderController {
             return Result.fail(ResultCode.INTERNAL_SERVER_ERROR);
         }
     }
-
+    
     @PostMapping("/app/list")
     @ApiOperation(value = "订单获取列表")
     public Result<List<StoreOrderVO>> appList(@RequestBody StoreOrderAppDTO dto) {
-
+        
         Long tokenUserId = AuthService.getTokenUserId(null);
         dto.setUserId(tokenUserId);
         PageHelper.startPage(dto.getPage(), dto.getSize());
@@ -183,13 +194,40 @@ public class AppOrderController {
         }
         return Result.success(pageInfo);
     }
-
+    
+    /**
+     * 获取用户可回收次数
+     */
+    @GetMapping("app/userCanRecycleNum")
+    public Result<Integer> getUserCanRecycleNum() {
+        Long tokenUserId = AuthService.getTokenUserId(null);
+        return Result.success(this.getUserCanRecycleNum(tokenUserId));
+    }
+    
+    /**
+     * 回收订单
+     */
+    @PostMapping("app/recycleOrder")
+    public Result recycleOrder(@RequestBody RecycleOrderRO ro) {
+        Long tokenUserId = AuthService.getTokenUserId(null);
+        Integer userCanRecycleNum = this.getUserCanRecycleNum(tokenUserId);
+        
+        // 校验可回收次数
+        if (userCanRecycleNum < ro.getOrderNos().size()) {
+            throw new ServiceException(I18nUtil.get("recycle.number.deficiency"));
+        }
+        storeOrderService.recycleOrder(ro.getOrderNos(), tokenUserId);
+        
+        return Result.success();
+    }
+    
+    
     @ApiOperation(value = "获取订单各状态数量")
     @GetMapping(value = "/status/num")
     public Result<StoreOrderCountItemVO> getOrderStatusNum() {
         return Result.success(storeOrderService.getOrderStatusNum());
     }
-
+    
     //    @ApiOperation("导出订单")
     //    @PostMapping("/export")
     //    public Result exportFile(@RequestBody StoreOrderDTO dto, HttpServletResponse response) {
@@ -203,7 +241,7 @@ public class AppOrderController {
     //        storeOrderService.refund(id);
     //        return Result.success();
     //    }
-
+    
     @ApiOperation("关闭订单")
     @PostMapping("/close")
     public Result close(@RequestParam("orderNo") String orderNo) {
@@ -213,7 +251,7 @@ public class AppOrderController {
         storeOrderService.close(orderNo);
         return Result.success();
     }
-
+    
     @ApiOperation("取消订单")
     @PostMapping("/cancel")
     public Result cancel(@RequestParam("orderNo") String orderNo) {
@@ -223,79 +261,109 @@ public class AppOrderController {
         storeOrderService.cancel(orderNo);
         return Result.success();
     }
-
+    
     @ApiOperation("联系用户")
     @PostMapping("/contactUser")
     public Result contactUser(@RequestParam("userId") Long userId) {
         //        storeOrderService.contactUser(userId);
         return Result.success();
     }
-
+    
     //    @ApiOperation("批量发货")
     //    @PostMapping("/batchDelivery")
     //    public Result batchDelivery(@RequestBody List<StoreOrderDeliveryDTO> list) {
     //        storeOrderService.batchDelivery(list);
     //        return Result.success();
     //    }
-
+    
     @ApiOperation(value = "预下单")
     @PostMapping(value = "/pre/order")
     public Result preOrder(@RequestBody @Validated PreOrderRequest request) {
         Long tokenUserId = AuthService.getTokenUserId(null);
         request.setUserId(tokenUserId);
         return Result.success(storeOrderService.preOrder(request));
-
+        
     }
-
+    
     @ApiOperation(value = "加载预下单")
     @PostMapping(value = "load/pre")
     public Result<PreOrderResponse> loadPreOrder(@RequestParam String preOrderNo) {
         if (ObjectUtils.isEmpty(preOrderNo)) {
             return Result.fail(ResultCode.CODE_IS_NULL);
         }
-
+        
         Long tokenUserId = AuthService.getTokenUserId(null);
         return Result.success(storeOrderService.loadPreOrder(preOrderNo));
     }
-
+    
     @ApiOperation(value = "计算订单价格")
     @PostMapping(value = "/computed/price")
     public Result<ComputedOrderPriceResponse> computedPrice(@Validated @RequestBody OrderComputedPriceRequest request) {
-
+        
         Long tokenUserId = AuthService.getTokenUserId(null);
         request.setUserId(tokenUserId);
         return Result.success(storeOrderService.computedOrderPrice(request));
     }
-
+    
     @ApiOperation(value = "去支付")
     @PostMapping(value = "/goPay")
     public Result getPayResult(@RequestBody GoPinkDTO dto) {
-
+        
         Long tokenUserId = AuthService.getTokenUserId(null);
         dto.setUserId(tokenUserId);
         return storeOrderService.goPay(dto);
     }
-
+    
     //    @ApiOperation("导出发货单")
     //    @PostMapping("/exportDelivery")
     //    public Result exportDelivery(HttpServletResponse response) {
     //        storeOrderService.exportDelivery(response);
     //        return Result.success();
     //    }
-
+    
     //    @ApiOperation("导入发货单")
     //    @PostMapping("/importDelivery")
     //    public Result importDelivery(@JSONField(serialize = false) @RequestParam("file") MultipartFile file) {
     //        storeOrderService.importDelivery(file);
     //        return Result.success();
     //    }
-
-
+    
+    
     @ApiOperation("待处理红点数")
     @GetMapping("/pendingRedDots")
     public Result pendingRedDots() {
         return Result.success(storeOrderService.pendingRedDots());
     }
-
-
+    
+    
+    /**
+     * 获取用户可回收次数
+     */
+    private Integer getUserCanRecycleNum(Long userId) {
+        // 用户总成功订单数
+        UserDTO user = userDubboServiceClient.getUser(userId);
+        // 用户总成功订单数
+        Integer totalNumberOfWin = user.getTotalNumberOfWin();
+        // 用户总回收订单数
+        Integer totalNumberOfRecycle = user.getTotalNumberOfRecycle();
+        
+        // 成功订单总数
+        Integer successTotalOrderNum = Integer.valueOf(configDubboServiceClient.getConfigByCode("success_total_order_num").getValueInfo());
+        // 回收数量
+        Integer recycleNum = Integer.valueOf(configDubboServiceClient.getConfigByCode("recycle_num").getValueInfo());
+        
+        if (successTotalOrderNum == 0) {
+            return 0;
+        }
+        
+        // 计算 totalNumberOfWin / successTotalOrderNum,向下取整(截断小数部分)
+        BigDecimal divisionResult = new BigDecimal(totalNumberOfWin).divide(new BigDecimal(successTotalOrderNum), 0, RoundingMode.DOWN);
+        
+        // 将商的整数部分乘以 totalNumberOfWin
+        BigDecimal calculatedValue = divisionResult.multiply(new BigDecimal(recycleNum));
+        
+        BigDecimal canRecycleNum = calculatedValue.subtract(new BigDecimal(totalNumberOfRecycle));
+        
+        return (canRecycleNum.compareTo(BigDecimal.ZERO) == 1) ? (canRecycleNum.intValue()) : 0;
+    }
 }

+ 31 - 8
mall-service/src/main/java/com/txz/mall/dubbo/client/CifUserDubboServiceClient.java

@@ -12,28 +12,51 @@ import java.util.List;
 @Slf4j
 @Component
 public class CifUserDubboServiceClient {
-
-
+    
+    
     @Reference
     private UserDubboService userDubboService;
-
+    
     /**
      * 获取用户信息
      *
      * @param userId
+     *
      * @return
      */
     public UserDTO getUser(Long userId) {
         return userDubboService.getUser(userId);
     }
     
-    public List<UserDTO> getUsersByIds(List<Long> userIds){
+    public List<UserDTO> getUsersByIds(List<Long> userIds) {
         return userDubboService.getUsersByIds(userIds);
     }
-
-    public ConfigMemberDTO getConfigByLevel(Integer var1){
+    
+    public ConfigMemberDTO getConfigByLevel(Integer var1) {
         return userDubboService.getConfigByLevel(var1);
     }
-
-
+    
+    
+    /**
+     * 添加中奖次数
+     */
+    public Boolean addNumberOfWin(Long userId) {
+        return userDubboService.addNumberOfWin(userId);
+    }
+    
+    /**
+     * 添加中奖次数
+     */
+    public Boolean addNumberOfWin(Long userId, Integer number) {
+        return userDubboService.addNumberOfWin(userId, number);
+    }
+    
+    /**
+     * 添加回收次数
+     */
+    public Boolean addNumberOfRecycle(Long userId, Integer number) {
+        return userDubboService.addNumberOfRecycle(userId, number);
+    }
+    
+    
 }

+ 3 - 3
mall-service/src/main/java/com/txz/mall/enums/PinkOrderStatusEnum.java

@@ -1,7 +1,5 @@
 package com.txz.mall.enums;
 
-import com.txz.mall.util.I18nUtil;
-
 import java.util.Objects;
 
 /**
@@ -28,7 +26,9 @@ public enum PinkOrderStatusEnum {
     GROUP_ORDER_TO_SHIP(5, "拼团待发货"),
     GROUP_ORDER_CLOSED(6, "拼团未中奖关闭"),
     GROUP_ORDER_TO_RECEIVE(7, "拼团待收货"),
-    GROUP_ORDER_COMPLETED(8, "拼团订单完成");
+    GROUP_ORDER_COMPLETED(8, "拼团订单完成"),
+    GROUP_ORDER_RECYCLE(9, "拼团订单回收"),
+    ;
 
     private Integer key;
     private String value;

+ 48 - 39
mall-service/src/main/java/com/txz/mall/service/StoreOrderService.java

@@ -11,174 +11,183 @@ import vo.*;
 
 import javax.servlet.http.HttpServletResponse;
 import java.util.List;
-import java.util.Map;
 
 
 /**
  * Created by CodeGenerator on 2025/07/15.
  */
 public interface StoreOrderService extends Service<StoreOrder> {
-
+    
     /**
      * 获取订单状态数量
      *
      * @return StoreOrderCountItemResponse
      */
     StoreOrderCountItemVO getOrderStatusNum();
-
+    
     /**
      * 去开团
      */
     void goOpen(String orderId, UserDTO user);
-
+    
     /**
      * 去拼团
      */
     void goPink(GoPinkDTO dto, UserDTO user);
-
+    
     /**
      * 导出订单
      *
      * @param response 响应
      */
     void exportFile(StoreOrderDTO dto, HttpServletResponse response);
-
+    
     /**
      * 批量发货
      */
     void batchDelivery(List<StoreOrderDeliveryDTO> dto);
-
+    
     /**
      * 获取订单详情
      *
      * @return StoreOrderVO
      */
     ComputedOrderPriceResponse computedOrderPrice(OrderComputedPriceRequest request);
-
+    
     /**
      * 订单预下单
      *
      * @param request 预下单请求参数
+     *
      * @return PreOrderResponse
      */
     String preOrder(PreOrderRequest request);
-
+    
     /**
      * 订单退款申请Task使用
      *
      * @param applyList 退款List
+     *
      * @return Boolean
      */
     Boolean refundApplyTask(List<OrderRefundApplyVO> applyList);
-
+    
     /**
      * 获取订单列表
      *
      * @return 订单列表
      */
     PageInfo<StoreOrderVO> orderList(StoreOrderDTO dto);
-
+    
     /**
      * 获取订单列表
      *
      * @return 订单列表
      */
     List<StoreOrderVO> appList(StoreOrderAppDTO dto);
-
+    
     /**
      * 获取用户当前的拼团订单
      *
      * @param uid 用户uid
+     *
      * @return 用户当前的拼团订单
      */
     List<StoreOrder> getUserCurrentCombinationOrders(Long uid, Long combinationId);
-
+    
     /**
      * 加载预下单信息
      *
      * @param preOrderNo 预下单号
+     *
      * @return 预下单信息
      */
     PreOrderResponse loadPreOrder(String preOrderNo);
-
+    
     /**
      * 创建订单
      *
      * @param orderRequest 创建订单请求参数
+     *
      * @return MyRecord 订单编号
      */
     MyRecord createOrder(CreateOrderRequest orderRequest);
-
+    
     /**
      * 获取支付结果
      */
     Result goPay(GoPinkDTO dto);
-
+    
     /**
      * 订单退款
      *
      * @param id 订单编号
      */
     void refund(String orderNo);
-
+    
     /**
      * 订单关闭
      *
      * @param id 订单编号
      */
     void close(String orderNo);
-
-
+    
+    
     /**
      * 定时订单关闭
      */
     void scheduledTaskStorePinkSummaryClose();
-
-
+    
+    
     /**
      * 订单取消
      *
      * @param orderNo 订单编号
      */
     void cancel(String orderNo);
-
-
+    
+    
     void orderTimeoutAutomaticCancel();
-
+    
     /**
      * 导出发货单
      */
     // void exportDelivery(HttpServletResponse response);
-
+    
     /**
      * 导入发货单
      */
     void importDelivery(MultipartFile file, HttpServletResponse response);
-
+    
     /**
      * 订单状态机
      */
     void updateOrderStatus(String orderNo, Integer status);
-
-
-
+    
+    
     void bindingAddress(StoreOrder storeOrder);
-
-
+    
+    
     void batchSigning();
-
+    
     /**
      * 待处理红点数
+     *
      * @return
      */
     PendingRedDotsVO pendingRedDots();
-
+    
     List<StoreCombinationRankVO> getRank();
-
+    
     List<StoreOrder> findByOrderIds(List<String> orderIds);
-
-  /**
-   * 事务补偿
-   */
-  void retryDistributedTxRecord();
+    
+    /**
+     * 事务补偿
+     */
+    void retryDistributedTxRecord();
+    
+    /**
+     * 回收订单
+     */
+    void recycleOrder(List<String> orderNos, Long userId);
 }

+ 45 - 0
mall-service/src/main/java/com/txz/mall/service/impl/StoreOrderServiceImpl.java

@@ -20,9 +20,11 @@ import com.txz.cif.dto.AccountDTO;
 import com.txz.cif.dto.ConfigMemberDTO;
 import com.txz.cif.dto.Result;
 import com.txz.cif.dto.UserDTO;
+import com.txz.cif.enums.BizTypeEnum;
 import com.txz.cif.param.CancelParam;
 import com.txz.cif.param.JoinParam;
 import com.txz.cif.param.OpenParam;
+import com.txz.cif.param.SignRedEnvelopeParam;
 import com.txz.mall.constants.Constants;
 import com.txz.mall.core.*;
 import com.txz.mall.core.cache.RedisKey;
@@ -31,6 +33,7 @@ import com.txz.mall.dao.StorePinkMapper;
 import com.txz.mall.dao.StorePinkSummaryMapper;
 import com.txz.mall.dubbo.client.CifAccountDubboServiceClient;
 import com.txz.mall.dubbo.client.CifUserDubboServiceClient;
+import com.txz.mall.dubbo.client.OperatingConfigDubboServiceClient;
 import com.txz.mall.enums.NoticeEnum;
 import com.txz.mall.enums.OrderEventsEnum;
 import com.txz.mall.enums.PinkOrderStatusEnum;
@@ -97,6 +100,8 @@ public class StoreOrderServiceImpl extends AbstractService<StoreOrder> implement
     @Resource
     private LockTemplate lockTemplate;
     
+    private final OperatingConfigDubboServiceClient configDubboServiceClient;
+    
     @Override
     public StoreOrderCountItemVO getOrderStatusNum() {
         StoreOrderCountItemVO response = new StoreOrderCountItemVO();
@@ -2753,5 +2758,45 @@ public class StoreOrderServiceImpl extends AbstractService<StoreOrder> implement
         }
     }
     
+    @Override
+    public void recycleOrder(List<String> orderNos, Long userId) {
+        
+        // 回收比例
+        BigDecimal recycleProportion = new BigDecimal(configDubboServiceClient.getConfigByCode("recycle_proportion").getValueInfo());
+        
+        // 校验订单
+        Condition conditionQuery = new Condition(StoreOrder.class);
+        Example.Criteria criteriaQuery = conditionQuery.createCriteria();
+        criteriaQuery.andEqualTo("isDelete", 0);
+        criteriaQuery.andEqualTo("uid", userId);
+        criteriaQuery.andEqualTo("status", PinkOrderStatusEnum.GROUP_ORDER_TO_PAY.getKey());
+        criteriaQuery.andIn("orderId", orderNos);
+        
+        List<StoreOrder> infoList = this.findByCondition(conditionQuery);
+        if (infoList.size() != orderNos.size()) {
+            throw new ServiceException(I18nUtil.get("recycle.order.number.error"));
+        }
+        
+        // 更新订单状态
+        Example.Criteria update = new Example(StoreOrder.class).createCriteria().andIn("orderId", orderNos);
+        StoreOrder storeOrder = new StoreOrder();
+        storeOrder.setStatus(PinkOrderStatusEnum.GROUP_ORDER_RECYCLE.getKey());
+        this.update(storeOrder, update);
+        // 添加回收数
+        userDubboServiceClient.addNumberOfRecycle(userId, orderNos.size());
+        
+        for (StoreOrder orders : infoList) {
+            // 添加收益
+            SignRedEnvelopeParam envelopeParam = new SignRedEnvelopeParam();
+            envelopeParam.setUserId(userId);
+            envelopeParam.setAmount(orders.getPayPrice().multiply(recycleProportion));
+            envelopeParam.setBizType(BizTypeEnum.RECYCLE);
+            envelopeParam.setTransTime(new Date());
+            envelopeParam.setOrderNo(orders.getOrderId());
+            accountDubboServiceClient.addRedEnvelope(envelopeParam);
+        }
+        
+    }
+    
     
 }

+ 216 - 213
mall-service/src/main/java/com/txz/mall/service/impl/StorePinkServiceImpl.java

@@ -28,7 +28,6 @@ import com.txz.mall.model.*;
 import com.txz.mall.service.*;
 import com.txz.mall.util.I18nUtil;
 import com.txz.mall.util.OrderStateMachine;
-import com.txz.mall.util.RandomUtil;
 import com.txz.mall.web.vo.ProductCarouselVO;
 import dto.ProductCarouselDTO;
 import lombok.extern.slf4j.Slf4j;
@@ -55,25 +54,25 @@ import java.util.stream.Collectors;
 @Transactional
 @Slf4j
 public class StorePinkServiceImpl extends AbstractService<StorePink> implements StorePinkService {
-
-
+    
+    
     @Resource
     private StorePinkMapper storePinkMapper;
-
+    
     @Resource
     private CifAccountDubboServiceClient cifAccountDubboServiceClient;
-
+    
     @Resource
     private CifUserDubboServiceClient userDubboServiceClient;
     @Resource
     private NoticeService noticeService;
-
+    
     @Resource
     private StoreProductMapper storeProductMapper;
-
+    
     @Resource
     private StoreCombinationMapper storeCombinationMapper;
-
+    
     @Override
     public List<StorePink> getListByCidAndKid(Long cid, Long kid) {
         Condition condition = new Condition(StorePink.class);
@@ -84,18 +83,17 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
         condition.setOrderByClause("id DESC");
         return findByCondition(condition);
     }
-
-
+    
+    
     @Resource
     private StorePinkSummaryService storePinkSummaryService;
     @Resource
     private DailySalesSummaryOfProductsService dailySalesSummaryOfProductsService;
-
+    
     @Override
     @Transactional
     public void pinkSuccess(String orderNo, StoreOrder storeOrder) {
-
-
+        
         // 现在这个方法每次支付的时候都会执行一次
         Date date = new Date();
         if (ObjectUtil.isNull(orderNo)) {
@@ -110,21 +108,21 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
         // storePink2.setStopTime(date);
         storePink2.setOrderStatus(PinkOrderStatusEnum.GROUP_ORDER_PAID.getKey());
         log.info("storePink2:" + storePink2);
-
+        
         Condition updateStorePinkCondition = new Condition(StorePink.class);
         updateStorePinkCondition.createCriteria().andEqualTo("orderId", orderNo);
         storePinkMapper.updateByConditionSelective(storePink2, updateStorePinkCondition);
         dailySalesSummaryOfProductsService.updateDailySalesSummaryOfProducts(orderNo, storePink2);
-
+        
         //**分库整改
         // update(storePink2);
-
+        
         storeOrderStatusService.createLog(storeOrder.getId(), storeOrder.getOrderId(), Constants.ORDER_LOG_PAY_SUCCESS, "支付成功");
         noticeService.addOrderNotice(NoticeEnum.ORDER_GROUP_BUY_PAYMENT_SUCCESS, storeOrder.getOrderId(), storeOrder.getUid());
-
+        
         // 累计虚拟销量,虚拟销量和下单数挂钩,和是否退款或者成团或者是否中奖都无关  只累加不扣减
         Long pid = teamPink.getPid();
-
+        
         StoreProduct storeProduct = storeProductService.findById(pid);
         StoreProduct storeProductForUpdate = new StoreProduct();
         storeProductForUpdate.setFicti(storeProduct.getFicti() + teamPink.getTotalNum());
@@ -135,34 +133,34 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
         if (i == 0) {
             throw new ServiceException(I18nUtil.get("failed.to.increase.virtual.sales.during.payment") + pid);
         }
-
+        
         // 将虚拟销量维护到拼团商品表上防止连表查询
         StoreCombination storeCombinationUpdate = new StoreCombination();
         storeCombinationUpdate.setFicti(storeProduct.getFicti() + teamPink.getTotalNum());
         Example exampleStoreCombination = new Example(StoreCombination.class);
         exampleStoreCombination.createCriteria().andEqualTo("productId", pid).andEqualTo("isDelete", 0);
         storeCombinationMapper.updateByConditionSelective(storeCombinationUpdate, exampleStoreCombination);
-
+        
         //  memberList.add(teamPink);
         //        memberList.forEach(i -> {
         //            i.setStatus(2);
         //            i.setStopTime(date);
         //            update(i);
         //        });
-
+        
         // 理论上在支付环节调用的时候不会出现拼团人数校验异常,所以这块调用这个方法的目的在于维护成团状态。 如果支付环节抛出了
         // 拼团校验异常则证明在 add时就有问题,没有挡住异常的拼团数据
         log.info("storePinkSummaryService.maintainQuantityStatusOfTheStorePinkSummary SpsId" + teamPink.getSpsCode());
         Boolean b = storePinkSummaryService.maintainQuantityStatusOfTheStorePinkSummary(teamPink.getSpsCode());
         log.info("storePinkSummaryService.maintainQuantityStatusOfTheStorePinkSummary b" + b);
         if (b) {
-
+            
             // 算出天选  同时推进订单状态到 代发货状态/订单关闭状态/未中奖成员退款
             theSelection(teamPink.getSpsCode(), date);
-
+            
         }
     }
-
+    
     //    @Override
     //    public void theSelection(String orderId) {
     //        // 假设只有1个用户是天选
@@ -205,11 +203,11 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
     @Lazy
     @Resource
     private StoreProductService storeProductService;
-
+    
     @Lazy
     @Resource
     private StoreOrderStatusService storeOrderStatusService;
-
+    
     @Override
     public void theSelection(String spsCode, Date date) {
         log.info("theSelection:" + spsCode);
@@ -246,199 +244,204 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
         List<OrderParam> orderParamList = new ArrayList<>();
         // 优化后:批量查询 StoreOrder
         List<String> orderIds = list.stream()
-          .map(StorePink::getOrderId)
-          .collect(Collectors.toList());
+                .map(StorePink::getOrderId)
+                .collect(Collectors.toList());
         Map<String, StoreOrder> orderMap = storeOrderService.findByOrderIds(orderIds)
-        .stream()
-        .collect(Collectors.toMap(StoreOrder::getOrderId, Function.identity()));
-        //1.随机筛选中奖者
-        List<StorePink> storePinks = selectWinners(list,1);
-        if(CollUtil.isNotEmpty(storePinks)){
-          StorePink winner = storePinks.get(0);
-          //2.中奖者
-          processWinner(orderMap, winner, param,date);
-          param.setTransTime(date);
-          //3.删除中奖者
-          list.removeIf(pink -> pink.getId().equals(winner.getId()));
-          //4.非中奖者处理
-          processLosers(orderMap, list, orderParamList, param, date);
-          log.info("orderParamList" + orderParamList);
-          param.setUserIds(orderParamList);
-          log.info("cifAccountDubboServiceClient.accomplishGroup" + JSONObject.toJSONString(param));
-          Result result = cifAccountDubboServiceClient.accomplishGroup(param);
-          log.info("cifAccountDubboServiceClient.accomplishGroup result" + result);
-          if (!result.getCode().equals("200")) {
-            throw new ServiceException(I18nUtil.get("refund.failed.for.users.who.did.not.win.the.group.buying.message") + result.getMessage());
-          }
+                .stream()
+                .collect(Collectors.toMap(StoreOrder::getOrderId, Function.identity()));
+        // 1.随机筛选中奖者
+        List<StorePink> storePinks = selectWinners(list, 1);
+        if (CollUtil.isNotEmpty(storePinks)) {
+            StorePink winner = storePinks.get(0);
+            // 2.中奖者
+            processWinner(orderMap, winner, param, date);
+            param.setTransTime(date);
+            // 3.删除中奖者
+            list.removeIf(pink -> pink.getId().equals(winner.getId()));
+            // 4.非中奖者处理
+            processLosers(orderMap, list, orderParamList, param, date);
+            log.info("orderParamList" + orderParamList);
+            param.setUserIds(orderParamList);
+            log.info("cifAccountDubboServiceClient.accomplishGroup" + JSONObject.toJSONString(param));
+            Result result = cifAccountDubboServiceClient.accomplishGroup(param);
+            log.info("cifAccountDubboServiceClient.accomplishGroup result" + result);
+            if (!result.getCode().equals("200")) {
+                throw new ServiceException(I18nUtil.get("refund.failed.for.users.who.did.not.win.the.group.buying.message") + result.getMessage());
+            }
         }
-
+        
     }
-
-  // 使用更高效的随机算法
-  private List<StorePink> selectWinners(List<StorePink> candidates, int winnerCount) {
-    if (CollectionUtils.isEmpty(candidates) || winnerCount <= 0) {
-      return Collections.emptyList();
-    }
-    // 如果候选者数量小于等于需要选择的数量,直接返回所有候选者
-    if (candidates.size() <= winnerCount) {
-      return new ArrayList<>(candidates);
+    
+    // 使用更高效的随机算法
+    private List<StorePink> selectWinners(List<StorePink> candidates, int winnerCount) {
+        if (CollectionUtils.isEmpty(candidates) || winnerCount <= 0) {
+            return Collections.emptyList();
+        }
+        // 如果候选者数量小于等于需要选择的数量,直接返回所有候选者
+        if (candidates.size() <= winnerCount) {
+            return new ArrayList<>(candidates);
+        }
+        // 使用Collections.shuffle进行随机打乱
+        List<StorePink> shuffled = new ArrayList<>(candidates);
+        Collections.shuffle(shuffled, new Random());
+        // 返回前winnerCount个作为中奖者
+        return shuffled.subList(0, winnerCount);
     }
-    // 使用Collections.shuffle进行随机打乱
-    List<StorePink> shuffled = new ArrayList<>(candidates);
-    Collections.shuffle(shuffled, new Random());
-    // 返回前winnerCount个作为中奖者
-    return shuffled.subList(0, winnerCount);
-  }
+    
     // 将大事务拆分为多个小事务
     @Transactional(propagation = Propagation.REQUIRES_NEW)
     public void processWinner(Map<String, StoreOrder> orderMap,
-                              StorePink storePink, AccomplishParam param,Date date) {
-      // 处理单个中奖者
-      StorePink luckPink = new StorePink();
-      StoreOrder storeOrder = orderMap.get(storePink.getOrderId());
-      if(storeOrder == null){
-        return;
-      }
-      luckPink.setId(storePink.getId());
-      luckPink.setLId(1);
-      luckPink.setStatus(StorePinkStatusEnum.RESULTS_ANNOUNCED.getKey());
-      luckPink.setStopTime(date);
-
-      PinkOrderStatusEnum pinkOrderStatusEnum = OrderStateMachine.handleEvent(storeOrder, OrderEventsEnum.GROUP_PURCHASE_WIN, null);
-      if (ObjectUtils.isEmpty(pinkOrderStatusEnum)) {
-        throw new ServiceException(I18nUtil.get("current.order.status.does.not.allow.progression.to.pending.shipment.orderid") + storePink.getOrderId());
-      }
-      if (!ObjectUtils.isEmpty(storeOrder.getAddressId())) {
-        luckPink.setOrderStatus(PinkOrderStatusEnum.GROUP_ORDER_TO_SHIP.getKey());
-        storeOrderService.updateOrderStatus(storePink.getOrderId(), pinkOrderStatusEnum.getKey());
-      } else {
-        noticeService.addOrderNotice(NoticeEnum.ORDER_PROVIDE_SHIPPING_ADDRESS, storeOrder.getOrderId(), storeOrder.getUid());
-      }
-      Condition storePinkUpdateCondition = new Condition(StorePink.class);
-      storePinkUpdateCondition.createCriteria().andEqualTo("orderId", storePink.getOrderId());
-      storePinkMapper.updateByConditionSelective(luckPink, storePinkUpdateCondition);
-      // 维护每日统计表
-      dailySalesSummaryOfProductsService.updateDailySalesSummaryOfProducts(storePink.getOrderId(), luckPink);
-      //异步添加日志
-      CompletableFuture.runAsync(() -> {
-        try {
-          storeOrderStatusService.createLog(storeOrder.getId(), storeOrder.getOrderId(), Constants.ORDER_STATUS_PINK_SUCCESS_ORDER, "拼团成功");
-          noticeService.addOrderNotice(NoticeEnum.ORDER_GROUP_BUY_SUCCESS_WIN, storeOrder.getOrderId(), storeOrder.getUid());
-        } catch (Exception e) {
-          log.error("异步处理订单后续操作异常,", e);
-        }
-      });
-      // 中奖者
-      param.setWinnerOrderNo(storeOrder.getOrderId());
-      param.setWinnerUserId(storeOrder.getUid());
-      Integer kId = storePink.getKId();
-      Integer zero = 0;
-      if (zero.equals(kId)) {
-        param.setOpenGroupUserId(storeOrder.getUid());
-        param.setOpenOrderNo(storeOrder.getOrderId());
-      }
-    }
-
-    @Transactional(propagation = Propagation.REQUIRES_NEW)
-    public void processLosers(Map<String, StoreOrder> orderMap,
-                              List<StorePink> loserPinks,
-                              List<OrderParam> orderParamList,
-                              AccomplishParam param,
-                              Date date) {
-      // 批量处理未中奖者
-      loserPinks.forEach(a -> {
-        log.info("forEach a:" + JSONObject.toJSONString(a));
-        StoreOrder storeOrder = orderMap.get(a.getOrderId());
-        if(storeOrder == null){
-          return;
+                              StorePink storePink, AccomplishParam param, Date date) {
+        // 处理单个中奖者
+        StorePink luckPink = new StorePink();
+        StoreOrder storeOrder = orderMap.get(storePink.getOrderId());
+        if (storeOrder == null) {
+            return;
         }
-        PinkOrderStatusEnum pinkOrderStatusEnum = OrderStateMachine.handleEvent(storeOrder, OrderEventsEnum.GROUP_PURCHASE_NOT_WIN, null);
+        luckPink.setId(storePink.getId());
+        luckPink.setLId(1);
+        luckPink.setStatus(StorePinkStatusEnum.RESULTS_ANNOUNCED.getKey());
+        luckPink.setStopTime(date);
+        
+        PinkOrderStatusEnum pinkOrderStatusEnum = OrderStateMachine.handleEvent(storeOrder, OrderEventsEnum.GROUP_PURCHASE_WIN, null);
         if (ObjectUtils.isEmpty(pinkOrderStatusEnum)) {
-          throw new ServiceException(I18nUtil.get("the.current.order.status.does.not.allow.advancement.to.the.closed.status.of.unwinning.orders.orderid") + a.getOrderId());
+            throw new ServiceException(I18nUtil.get("current.order.status.does.not.allow.progression.to.pending.shipment.orderid") + storePink.getOrderId());
         }
-        StorePink unLuckPink = new StorePink();
-        unLuckPink.setId(a.getId());
-        unLuckPink.setStatus(StorePinkStatusEnum.RESULTS_ANNOUNCED.getKey());
-        unLuckPink.setOrderStatus(pinkOrderStatusEnum.getKey());
-        unLuckPink.setStopTime(date);
-        Condition storePinkConditionForUpdate = new Condition(StorePink.class);
-        storePinkConditionForUpdate.createCriteria().andEqualTo("orderId", a.getOrderId());
-        storePinkMapper.updateByConditionSelective(unLuckPink, storePinkConditionForUpdate);
+        if (!ObjectUtils.isEmpty(storeOrder.getAddressId())) {
+            luckPink.setOrderStatus(PinkOrderStatusEnum.GROUP_ORDER_TO_SHIP.getKey());
+            storeOrderService.updateOrderStatus(storePink.getOrderId(), pinkOrderStatusEnum.getKey());
+        } else {
+            noticeService.addOrderNotice(NoticeEnum.ORDER_PROVIDE_SHIPPING_ADDRESS, storeOrder.getOrderId(), storeOrder.getUid());
+        }
+        Condition storePinkUpdateCondition = new Condition(StorePink.class);
+        storePinkUpdateCondition.createCriteria().andEqualTo("orderId", storePink.getOrderId());
+        storePinkMapper.updateByConditionSelective(luckPink, storePinkUpdateCondition);
         // 维护每日统计表
-        dailySalesSummaryOfProductsService.updateDailySalesSummaryOfProducts(a.getOrderId(), unLuckPink);
-        // 推进订单状态到未中奖关闭状态
-        log.info("storeOrderService.updateOrderStatus" + JSONObject.toJSONString(a));
-        storeOrderService.updateOrderStatus(a.getOrderId(), pinkOrderStatusEnum.getKey());
-//        storeOrderStatusService.createLog(storeOrder.getId(), storeOrder.getOrderId(), Constants.ORDER_STATUS_PINK_SUCCESS_ORDER, "拼团成功");
-//        noticeService.addOrderNotice(NoticeEnum.ORDER_GROUP_BUY_SUCCESS_LOSE, storeOrder.getOrderId(), storeOrder.getUid());
-        // 库存回退
-//        // 拼团商品扣库存
-//        log.info("storeCombinationService.operationStock" + JSONObject.toJSONString(a));
-//        storeCombinationService.operationStock(a.getCid(), a.getTotalNum(), "add");
-//        // 普通商品口库存
-//        log.info("storeProductService.operationStock" + JSONObject.toJSONString(a));
-//        storeProductService.operationStock(a.getPid(), a.getTotalNum(), "add");
-        // 非天选之子给他退款
-        OrderParam orderParam = new OrderParam();
-        orderParam.setOrderId(storeOrder.getId() + "");
-        orderParam.setUserId(storeOrder.getUid());
-        orderParam.setOrderNo(storeOrder.getOrderId());
-        Integer kId = a.getKId();
+        dailySalesSummaryOfProductsService.updateDailySalesSummaryOfProducts(storePink.getOrderId(), luckPink);
+        // 异步添加日志
+        CompletableFuture.runAsync(() -> {
+            try {
+                storeOrderStatusService.createLog(storeOrder.getId(), storeOrder.getOrderId(), Constants.ORDER_STATUS_PINK_SUCCESS_ORDER, "拼团成功");
+                noticeService.addOrderNotice(NoticeEnum.ORDER_GROUP_BUY_SUCCESS_WIN, storeOrder.getOrderId(), storeOrder.getUid());
+            } catch (Exception e) {
+                log.error("异步处理订单后续操作异常,", e);
+            }
+        });
+        // 中奖者
+        param.setWinnerOrderNo(storeOrder.getOrderId());
+        param.setWinnerUserId(storeOrder.getUid());
+        Integer kId = storePink.getKId();
         Integer zero = 0;
         if (zero.equals(kId)) {
-          param.setOpenGroupUserId(storeOrder.getUid());
-          param.setOpenOrderNo(storeOrder.getOrderId());
+            param.setOpenGroupUserId(storeOrder.getUid());
+            param.setOpenOrderNo(storeOrder.getOrderId());
+        }
+        // 添加中奖次数
+        if (!userDubboServiceClient.addNumberOfWin(storeOrder.getUid())) {
+            log.error("添加中奖次数失败" + storeOrder.getUid() + ",OrderId" + storeOrder.getOrderId());
         }
-        // 当前只能拼1个商品 所以理论上这个价格都是一样的,这边就循环覆盖即可
-        param.setAmount(storeOrder.getPayPrice());
-        orderParamList.add(orderParam);
-      });
-      //1.库存处理
-      //实际买的sku 都是一样的。库存处理
-      // 批量处理库存回退
-      Map<Long, Integer> combinationStockMap = loserPinks.stream()
-        .collect(Collectors.groupingBy(
-          StorePink::getCid,
-          Collectors.summingInt(StorePink::getTotalNum)
-        ));
-      Map<Long, Integer> productStockMap = loserPinks.stream()
-        .collect(Collectors.groupingBy(
-          StorePink::getPid,
-          Collectors.summingInt(StorePink::getTotalNum)
-        ));
-      // 批量更新库存
-      combinationStockMap.forEach((cid, num) ->
-        storeCombinationService.operationStock(cid, num, "add"));
-      productStockMap.forEach((pid, num) ->
-        storeProductService.operationStock(pid, num, "add"));
-      //2.异步添加日志
-      asyncProcessOrder(orderMap,loserPinks);
     }
-
-  // 异步处理非关键业务逻辑
-  private void asyncProcessOrder(Map<String, StoreOrder> orderMap,
-                                 List<StorePink> loserPinks) {
-    // 使用线程池异步处理日志记录、通知等非关键业务
-    CompletableFuture.runAsync(() -> {
-      try {
+    
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    public void processLosers(Map<String, StoreOrder> orderMap,
+                              List<StorePink> loserPinks,
+                              List<OrderParam> orderParamList,
+                              AccomplishParam param,
+                              Date date) {
+        // 批量处理未中奖者
         loserPinks.forEach(a -> {
+            log.info("forEach a:" + JSONObject.toJSONString(a));
             StoreOrder storeOrder = orderMap.get(a.getOrderId());
             if (storeOrder == null) {
-              return;
+                return;
             }
-          storeOrderStatusService.createLog(storeOrder.getId(), storeOrder.getOrderId(), Constants.ORDER_STATUS_PINK_SUCCESS_ORDER, "拼团成功");
-          noticeService.addOrderNotice(NoticeEnum.ORDER_GROUP_BUY_SUCCESS_LOSE, storeOrder.getOrderId(), storeOrder.getUid());
-          });
-      } catch (Exception e) {
-        log.error("异步处理订单后续操作异常,", e);
-      }
-    });
-  }
-
-
+            PinkOrderStatusEnum pinkOrderStatusEnum = OrderStateMachine.handleEvent(storeOrder, OrderEventsEnum.GROUP_PURCHASE_NOT_WIN, null);
+            if (ObjectUtils.isEmpty(pinkOrderStatusEnum)) {
+                throw new ServiceException(I18nUtil.get("the.current.order.status.does.not.allow.advancement.to.the.closed.status.of.unwinning.orders.orderid") + a.getOrderId());
+            }
+            StorePink unLuckPink = new StorePink();
+            unLuckPink.setId(a.getId());
+            unLuckPink.setStatus(StorePinkStatusEnum.RESULTS_ANNOUNCED.getKey());
+            unLuckPink.setOrderStatus(pinkOrderStatusEnum.getKey());
+            unLuckPink.setStopTime(date);
+            Condition storePinkConditionForUpdate = new Condition(StorePink.class);
+            storePinkConditionForUpdate.createCriteria().andEqualTo("orderId", a.getOrderId());
+            storePinkMapper.updateByConditionSelective(unLuckPink, storePinkConditionForUpdate);
+            // 维护每日统计表
+            dailySalesSummaryOfProductsService.updateDailySalesSummaryOfProducts(a.getOrderId(), unLuckPink);
+            // 推进订单状态到未中奖关闭状态
+            log.info("storeOrderService.updateOrderStatus" + JSONObject.toJSONString(a));
+            storeOrderService.updateOrderStatus(a.getOrderId(), pinkOrderStatusEnum.getKey());
+            //        storeOrderStatusService.createLog(storeOrder.getId(), storeOrder.getOrderId(), Constants.ORDER_STATUS_PINK_SUCCESS_ORDER, "拼团成功");
+            //        noticeService.addOrderNotice(NoticeEnum.ORDER_GROUP_BUY_SUCCESS_LOSE, storeOrder.getOrderId(), storeOrder.getUid());
+            // 库存回退
+            //        // 拼团商品扣库存
+            //        log.info("storeCombinationService.operationStock" + JSONObject.toJSONString(a));
+            //        storeCombinationService.operationStock(a.getCid(), a.getTotalNum(), "add");
+            //        // 普通商品口库存
+            //        log.info("storeProductService.operationStock" + JSONObject.toJSONString(a));
+            //        storeProductService.operationStock(a.getPid(), a.getTotalNum(), "add");
+            // 非天选之子给他退款
+            OrderParam orderParam = new OrderParam();
+            orderParam.setOrderId(storeOrder.getId() + "");
+            orderParam.setUserId(storeOrder.getUid());
+            orderParam.setOrderNo(storeOrder.getOrderId());
+            Integer kId = a.getKId();
+            Integer zero = 0;
+            if (zero.equals(kId)) {
+                param.setOpenGroupUserId(storeOrder.getUid());
+                param.setOpenOrderNo(storeOrder.getOrderId());
+            }
+            // 当前只能拼1个商品 所以理论上这个价格都是一样的,这边就循环覆盖即可
+            param.setAmount(storeOrder.getPayPrice());
+            orderParamList.add(orderParam);
+        });
+        // 1.库存处理
+        // 实际买的sku 都是一样的。库存处理
+        // 批量处理库存回退
+        Map<Long, Integer> combinationStockMap = loserPinks.stream()
+                .collect(Collectors.groupingBy(
+                        StorePink::getCid,
+                        Collectors.summingInt(StorePink::getTotalNum)
+                ));
+        Map<Long, Integer> productStockMap = loserPinks.stream()
+                .collect(Collectors.groupingBy(
+                        StorePink::getPid,
+                        Collectors.summingInt(StorePink::getTotalNum)
+                ));
+        // 批量更新库存
+        combinationStockMap.forEach((cid, num) ->
+                storeCombinationService.operationStock(cid, num, "add"));
+        productStockMap.forEach((pid, num) ->
+                storeProductService.operationStock(pid, num, "add"));
+        // 2.异步添加日志
+        asyncProcessOrder(orderMap, loserPinks);
+    }
+    
+    // 异步处理非关键业务逻辑
+    private void asyncProcessOrder(Map<String, StoreOrder> orderMap,
+                                   List<StorePink> loserPinks) {
+        // 使用线程池异步处理日志记录、通知等非关键业务
+        CompletableFuture.runAsync(() -> {
+            try {
+                loserPinks.forEach(a -> {
+                    StoreOrder storeOrder = orderMap.get(a.getOrderId());
+                    if (storeOrder == null) {
+                        return;
+                    }
+                    storeOrderStatusService.createLog(storeOrder.getId(), storeOrder.getOrderId(), Constants.ORDER_STATUS_PINK_SUCCESS_ORDER, "拼团成功");
+                    noticeService.addOrderNotice(NoticeEnum.ORDER_GROUP_BUY_SUCCESS_LOSE, storeOrder.getOrderId(), storeOrder.getUid());
+                });
+            } catch (Exception e) {
+                log.error("异步处理订单后续操作异常,", e);
+            }
+        });
+    }
+    
+    
     @Override
     public List<StorePinkOngoingVO> ongoingList(StorePink storePink) {
-
+        
         PageHelper.startPage(1, 3);
         List<StorePinkOngoingVO> list = new ArrayList<>();
         Condition storePinkSummarycondition = new Condition(StorePinkSummary.class);
@@ -448,14 +451,14 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
         storePinkSummarycriteria.andEqualTo("isVirtual", 0);
         storePinkSummarycondition.setOrderByClause("people_count DESC");
         List<StorePinkSummary> byCondition = storePinkSummaryService.findByCondition(storePinkSummarycondition);
-
-
+        
+        
         if (!CollectionUtils.isEmpty(byCondition)) {
-
+            
             Map<Long, StorePinkSummary> storePinkSummaryMap = byCondition.stream().collect(Collectors.toMap(StorePinkSummary::getId, a -> a, (b, c) -> c));
-
+            
             List<Long> spsIdList = byCondition.stream().map(StorePinkSummary::getId).collect(Collectors.toList());
-
+            
             List<String> orderNoSetList = byCondition.stream().map(StorePinkSummary::getOrderNoSet).filter(a -> !ObjectUtils.isEmpty(a)).collect(Collectors.toList());
             Set<String> orderNoSetForSearch = new HashSet<>();
             log.info("ongoingList.orderNoSetList:" + orderNoSetList);
@@ -472,18 +475,18 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
             // criteria.andEqualTo("cid", storePink.getCid());
             criteria.andEqualTo("orderStatus", PinkOrderStatusEnum.GROUP_ORDER_PAID.getKey());
             //  criteria.andEqualTo("kid", 0);
-
+            
             if (!org.springframework.util.CollectionUtils.isEmpty(orderNoSetForSearch)) {
                 criteria.andIn("orderId", orderNoSetForSearch);
             } else {
                 criteria.andIn("spsId", spsIdList);
             }
             List<StorePink> pinkList = findByCondition(condition);
-
+            
             Map<Long, List<StorePink>> collect = pinkList.stream().collect(Collectors.groupingBy(StorePink::getSpsId));
             list = pinkList.stream().filter(a -> a.getKId().equals(0)).map(a -> {
                 List<StorePink> storePinks = collect.get(a.getSpsId());
-
+                
                 StorePinkOngoingVO pinkOngoingVO = new StorePinkOngoingVO();
                 pinkOngoingVO.setId(a.getId());
                 pinkOngoingVO.setOrderId(a.getOrderId());
@@ -494,17 +497,17 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
                 pinkOngoingVO.setSuccessAvatar(storePinks.stream().map(StorePink::getAvatar).collect(Collectors.toList()));
                 return pinkOngoingVO;
             }).collect(Collectors.toList());
-
+            
             list = list.stream().sorted(Comparator.comparing(StorePinkOngoingVO::getRemainNum).reversed()).collect(Collectors.toList());
-
+            
         }
-
+        
         return list;
     }
-
+    
     @Resource
     private DailySalesSummaryOfProductsMapper dailySalesSummaryOfProductsMapper;
-
+    
     @Override
     public List<ProductCarouselVO> carousel(Long productId) {
         List<ProductCarouselDTO> pinks = dailySalesSummaryOfProductsMapper.pinkByProductId(productId);
@@ -522,7 +525,7 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
             return new ArrayList<>();
         }
         Map<Long, UserDTO> userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, user -> user));
-
+        
         List<ProductCarouselVO> carousel = new ArrayList<>();
         pinks.forEach(item -> {
             UserDTO user = userMap.get(item.getUid());
@@ -549,5 +552,5 @@ public class StorePinkServiceImpl extends AbstractService<StorePink> implements
         });
         return carousel;
     }
-
+    
 }

+ 20 - 0
mall-service/src/main/java/com/txz/mall/web/ro/RecycleOrderRO.java

@@ -0,0 +1,20 @@
+package com.txz.mall.web.ro;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2026/1/8
+ */
+@Data
+public class RecycleOrderRO {
+    
+    /**
+     * 回收订单
+     */
+    private List<String> orderNos;
+    
+}

+ 4 - 0
mall-service/src/main/resources/i18n/messages_bn_BD.properties

@@ -197,3 +197,7 @@ exception.summary=\u09AC\u09CD\u09AF\u09A4\u09BF\u0995\u09CD\u09B0\u09AE \u09B8\
 
 
 insufficient.balance=insufficient\u0020balance
+
+recycle.number.deficiency=\u09aa\u09c1\u09a8\u09b0\u09cd\u09a8\u09ac\u09c0\u09a8\u09c0\u0995\u09b0\u09a3\u09c7\u09b0 \u09b8\u0982\u0996\u09cd\u09af\u09be \u0985\u09aa\u09b0\u09cd\u09af\u09be\u09aa\u09cd\u09a4
+
+recycle.order.number.error=\u09b0\u09bf\u09b8\u09be\u0987\u0995\u09b2 \u0985\u09b0\u09cd\u09a1\u09be\u09b0 \u09a4\u09cd\u09b0\u09c1\u099f\u09bf\u09ac\u09bf\u09b9\u09c0\u09a8, \u09ab\u09cd\u09b0\u09c7\u09b6 \u0995\u09b0\u09c7 \u0986\u09ac\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8

+ 4 - 0
mall-service/src/main/resources/i18n/messages_en_US.properties

@@ -183,3 +183,7 @@ no.matching.table.found=no matching table found:
 table.key=, table key:
 
 insufficient.balance=insufficient balance
+
+recycle.number.deficiency=Insufficient recycling times
+
+recycle.order.number.error=The recovery order is incorrect. Please refresh and try again

+ 4 - 0
mall-service/src/main/resources/i18n/messages_zh_CN.properties

@@ -179,3 +179,7 @@ no.matching.table.found=\u672A\u627E\u5230\u5339\u914D\u7684\u8868:
 table.key=, \u5206\u8868\u952E:
 
 insufficient.balance=\u4F59\u989D\u4E0D\u8DB3
+
+recycle.number.deficiency=\u56de\u6536\u6b21\u6570\u4e0d\u8db3
+
+recycle.order.number.error=\u56de\u6536\u8ba2\u5355\u9519\u8bef\uff0c\u5237\u65b0\u540e\u518d\u8bd5