package com.tzy.controller.group;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.tzy.annotation.ApiLimitRule;
import com.tzy.annotation.ApiLog;
import com.tzy.annotation.RequireRoles;
import com.tzy.app.domain.act.ActSaleCode;
import com.tzy.app.domain.act.SaleCodeRecord;
import com.tzy.app.dto.ExtraInfoDTO;
import com.tzy.app.dto.InfoActConfig;
import com.tzy.app.dto.MerchantSortDTO;
import com.tzy.app.dto.group.BaseMerchantDTO;
import com.tzy.app.dto.group.MerchantGroupDTO;
import com.tzy.app.mapper.OrderListMapper;
import com.tzy.common.config.QuerySql;
import com.tzy.common.config.handle.ApiVersion;
import com.tzy.common.constant.ActConstans;
import com.tzy.common.constant.Constants;
import com.tzy.common.constant.MqConstans;
import com.tzy.common.constant.MsgConstants;
import com.tzy.common.core.domain.entity.SysDictData;
import com.tzy.common.dto.*;
import com.tzy.common.dto.act.CheckSaleCodeDTO;
import com.tzy.common.dto.act.GroupSaleCodeDTO;
import com.tzy.common.dto.group.GroupOrderUserDTO;
import com.tzy.common.dto.group.GroupQuery;
import com.tzy.common.dto.group.SimpleGroupGoodsDTO;
import com.tzy.common.enums.BusinessType;
import com.tzy.common.exception.AppAssert;
import com.tzy.common.exception.ServiceException;
import com.tzy.common.utils.DateUtils;
import com.tzy.common.utils.StringUtils;
import com.tzy.common.utils.UserType;
import com.tzy.common.utils.UserUtils;
import com.tzy.common.utils.bean.JSONTools;
import com.tzy.framework.util.RedisTools;
import com.tzy.framework.util.RedisUtils;
import com.tzy.framework.web.domain.LimitRule;
import com.tzy.ierp.domain.PyErpRandomCode;
import com.tzy.ierp.dto.ChecklistConfigDto;
import com.tzy.ierp.dto.PyErpRandomCodeReq;
import com.tzy.ierp.dto.RandomCodeMerInReq;
import com.tzy.ierp.enums.PyRandomCodeEnums;
import com.tzy.ierp.service.PyErpRandomCodeService;
import com.tzy.pojo.card.CardGroupGoods;
import com.tzy.sportcard.api.domain.AppUserInfoDto;
import com.tzy.sportcard.api.domain.GoodsInfo;
import com.tzy.sportcard.api.domain.GroupInfo;
import com.tzy.sportcard.api.domain.MerchantInfo;
import com.tzy.sportcard.api.dto.group.RecommendInfoDTO;
import com.tzy.sportcard.api.dto.group.SearchAdDTO;
import com.tzy.sportcard.api.dto.merchant.ActGoods;
import com.tzy.sportcard.api.service.*;
import com.tzy.sportcard.base.service.CommonCacheService;
import com.tzy.sportcard.enums.GroupOrderStatusEnums;
import com.tzy.sportcard.group.domain.CardGroupInfo;
import com.tzy.sportcard.group.domain.CardGroupOrderInfo;
import com.tzy.sportcard.group.service.ICardGroupInfoService;
import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
import com.tzy.sportcard.group.service.ITzyMerchantInfoService;
import com.tzy.sportcard.group.service.impl.GroupActService;
import com.tzy.system.service.ISysDictDataService;
import com.tzy.util.mq.MqUtils;
import com.tzy.valid.Insert;
import com.tzy.valid.Select;
import com.tzy.valid.Update;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.common.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.teasoft.bee.osql.*;
import org.teasoft.honey.osql.core.ConditionImpl;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author by po'yi
 * @Classname GroupControllerNew
 * @Description
 * @Date 2022/4/26 13:24
 */
@Api(value = "组团新接口")
@RestController
@RequestMapping("/api/{version}/group")
@Slf4j
public class GroupControllerNew {

    @Autowired
    private MineApiService mineApiService;
    @Autowired
    private SuidRich suidRich;
    @Autowired
    private PreparedSql preparedSql;
    @Autowired
    private GroupApiService groupApiService;
    @Autowired
    private ISysDictDataService dictDataService;
    @Resource
    private OrderListMapper orderListMapper;
    @Autowired
    private ICardGroupInfoService cardGroupInfoService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private ICardGroupOrderInfoService orderInfoService;
    @Resource
    private ITzyMerchantInfoService merchantInfoService;
    @Resource
    private IAppAdConfigService adConfigService;
    @Autowired
    @Qualifier("threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor pools;
    @Resource
    private CommonCacheService commonCacheService;
    @Resource
    private GroupActService groupActService;
    @Resource
    private PyErpRandomCodeService pyErpRandomCodeService;
    @Autowired
    private MerchantApiService merchantApiService;
    @Autowired
    private AsyncAppService asyncAppService;


    /**
     * @return
     * @throws Exception
     */
    @ApiLog(title = "拼团排名", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @PostMapping(value = "/info/rank")
    @ApiVersion(3.2)
    public OutDTO getGroupInfoRankV5(@RequestBody GroupInfo groupInfo) {
        if (groupInfo == null || groupInfo.getId() == null) {
            return OutDTO.error500("拼团id为空");
        }
        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectCardGroupInfoById(groupInfo.getId());
        if (cardGroupInfo == null) {
            return OutDTO.error500("拼团不存在");
        }
        if (cardGroupInfo.getPaniniListId() == null) {
            return OutDTO.ok().put("rankInfo", null);
        }
        GoodsInfo goodsInfo = new GoodsInfo();
        goodsInfo.setId(cardGroupInfo.getId().intValue());
        goodsInfo.setMerchantId(cardGroupInfo.getMerchantId().longValue());
        goodsInfo.setSport(cardGroupInfo.getSport());
        goodsInfo.setPaniniBaseId(cardGroupInfo.getPaniniListId().intValue());
        goodsInfo.setStatus(cardGroupInfo.getStatus().intValue());
        List<GoodsInfo> infos = Collections.singletonList(goodsInfo);
        groupApiService.getGroupRankV5(infos);
        return OutDTO.ok().put("rankInfo", infos.get(0).getRankInfo());
    }

    /**
     * @return
     * @throws Exception
     */
    @ApiLog(title = "拼团排名", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @PostMapping(value = "/info/rank")
    @ApiVersion(3.1)
    public OutDTO getGroupInfoRank(@RequestBody GroupInfo groupInfo) {
        if (groupInfo == null || groupInfo.getId() == null) {
            return OutDTO.error500("拼团id为空");
        }
        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectCardGroupInfoById(groupInfo.getId());
        if (cardGroupInfo == null) {
            return OutDTO.error500("拼团不存在");
        }
        if (cardGroupInfo.getPaniniListId() == null) {
            return OutDTO.ok().put("rankInfo", null);
        }
        GoodsInfo goodsInfo = new GoodsInfo();
        goodsInfo.setId(cardGroupInfo.getId().intValue());
        goodsInfo.setMerchantId(cardGroupInfo.getMerchantId().longValue());
        goodsInfo.setSport(cardGroupInfo.getSport());
        goodsInfo.setPaniniBaseId(cardGroupInfo.getPaniniListId().intValue());
        goodsInfo.setStatus(cardGroupInfo.getStatus().intValue());
        List<GoodsInfo> infos = Collections.singletonList(goodsInfo);
        groupApiService.getGroupRank(infos);
        return OutDTO.ok().put("rankInfo", infos.get(0).getRankInfo());
    }

    /**
     * 组团es
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "组团列表搜索-es版", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @PostMapping(value = "/list/search")
    @ApiVersion(1.1)
    @ApiLimitRule(seconds = 1, limitCount = 90)
    public OutDTO searchGroupByEsV3(@RequestBody InDto inDto) throws Exception {
        GroupQuery query = inDto.buildParam(new GroupQuery());
        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
        OutDTO result = OutDTO.ok();
        if (query.isRecommendFlag()) {
            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
                query.setSortIds(recommendInfo.getIds());
                result.put("recId", recommendInfo.getRecId());
                query.setPageNo(1);
            }
        }
        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
        List<GoodsInfo> infos = groupApiService.searchGroupByEs(query);
        ExtraInfoDTO extraInfo = future.get();
        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
        if (query.isTeamActQuery()) {
            // 球队活动页,数据按商家聚合重组
            buildInfoByMerchant(infos, result);
            infos = null;
        }
        result.put("merchants", extraInfo.getMerchants());
        return result.put("cardGroupInfos", infos).put("ref", "es");
    }

    /**
     * 组团es
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "组团列表搜索-es版", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @PostMapping(value = "/list/search")
    @ApiVersion(3.1)
    @ApiLimitRule(seconds = 1, limitCount = 90)
    public OutDTO searchGroupByEsV4(@RequestBody InDto inDto) throws Exception {
        GroupQuery query = inDto.buildParam(new GroupQuery());
        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
        OutDTO result = OutDTO.ok();
        if (query.isRecommendFlag()) {
            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
                query.setSortIds(recommendInfo.getIds());
                result.put("recId", recommendInfo.getRecId());
                query.setPageNo(1);
            }
        }
        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
        List<GoodsInfo> infos = groupApiService.searchGroupByEs(query);
        ExtraInfoDTO extraInfo = future.get();
        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
        if (query.isTeamActQuery()) {
            // 球队活动页,数据按商家聚合重组
            buildInfoByMerchant(infos, result);
            infos = null;
        }
        result.put("merchants", extraInfo.getMerchants());
        groupApiService.getGroupRank(infos);
        return result.put("cardGroupInfos", infos).put("ref", "es");
    }

    /**
     * 组团es
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "组团列表搜索-es版", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @PostMapping(value = "/list/search")
    @ApiVersion(3.2)
    @ApiLimitRule(seconds = 1, limitCount = 90)
    public OutDTO searchGroupByEsV5(@RequestBody InDto inDto) throws Exception {
        GroupQuery query = inDto.buildParam(new GroupQuery());
        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
        OutDTO result = OutDTO.ok();
        if (query.isRecommendFlag()) {
            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
                query.setSortIds(recommendInfo.getIds());
                result.put("recId", recommendInfo.getRecId());
                query.setPageNo(1);
            }
        }
        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
        List<GoodsInfo> infos = groupApiService.searchGroupByEs(query);
        ExtraInfoDTO extraInfo = future.get();
        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
        if (query.isTeamActQuery()) {
            // 球队活动页,数据按商家聚合重组
            buildInfoByMerchant(infos, result);
            infos = null;
        }
        result.put("merchants", extraInfo.getMerchants());
        groupApiService.getGroupRankV5(infos);
        return result.put("cardGroupInfos", infos).put("ref", "es");
    }


    /**
     * 组团es
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "组团列表搜索-分页key版", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @PostMapping(value = "/list/search")
    @ApiVersion(4.3)
    @ApiLimitRule(seconds = 1, limitCount = 400)
    public OutDTO searchGroupByEsV6(@RequestBody InDto inDto) throws Exception {
        String markId = inDto.getString("markId");
        String excludedIdsStr = inDto.getString("excludedids");
        List<Long> markIdList = new ArrayList<>();

        GroupQuery query = inDto.buildParam(new GroupQuery());
        if (!Strings.isEmpty(markId)) {
            markIdList = (List<Long>)redisUtils.get(Constants.APP_SEARCH_CACHE_KEY+markId);
            query.setExcludeInfoIds(markIdList);
        }else if((!Strings.isEmpty(markId))){
            List<String> excludedIds = Arrays.asList(excludedIdsStr.split(","));
            // 批量构建 Redis Key
            List<String> redisKeys = excludedIds.stream()
                    .map(id -> Constants.APP_SEARCH_CACHE_KEY + id)
                    .collect(Collectors.toList());
            // 批量查询（假设 redisUtils 支持批量操作）
            List<Object> results = redisUtils.multiGet(redisKeys);  // 需要自定义 redisUtils 方法实现
            // 合并结果（处理类型安全）
            markIdList = results.stream()
                    .filter(Objects::nonNull)          // 过滤 null 值
                    .filter(obj -> obj instanceof List)// 确保是 List 类型
                    .flatMap(obj -> ((List<?>) obj).stream())
                    .filter(Long.class::isInstance)    // 确保元素为 Long 类型
                    .map(Long.class::cast)
                    .distinct()                        // 去重（底层基于 equals/hashCode）
                    .collect(Collectors.toList());     // 转 List
            query.setInfoIds(markIdList);
        }
        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
        OutDTO result = OutDTO.ok();
        if (query.isRecommendFlag()) {
            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
                query.setSortIds(recommendInfo.getIds());
                result.put("recId", recommendInfo.getRecId());
                query.setPageNo(1);
            }
        }

        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
        List<GoodsInfo> infos = groupApiService.searchGroupByEs(query);
        ExtraInfoDTO extraInfo = future.get();
        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
        if (query.isTeamActQuery()) {
            // 球队活动页,数据按商家聚合重组
            buildInfoByMerchant(infos, result);
            infos = null;
        }
        result.put("merchants", extraInfo.getMerchants());
        groupApiService.getGroupRankV5(infos);
        UUID uuid = UUID.randomUUID();
        List<Long> idList = infos.stream()
                .map(GoodsInfo::getId).mapToLong(id -> id).boxed()
                .collect(Collectors.toList());
        if(markIdList!=null){idList.addAll(markIdList);}
        redisUtils.set(Constants.APP_SEARCH_CACHE_KEY+uuid, idList, 10*60);
        return result.put("cardGroupInfos", infos).put("ref", "es").put("markId", uuid).put("markLength", idList.size());
    }

    /**
     * 组团es
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "指定优惠券拼团列表", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @PostMapping(value = "/list/coupon")
    @ApiVersion(3.9)
    @ApiLimitRule(seconds = 1, limitCount = 90)
    public OutDTO searchCouponGroupByEs(@RequestBody InDto inDto) throws Exception {
        GroupQuery query = inDto.buildParam(new GroupQuery());
        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
        OutDTO result = OutDTO.ok();
        if (query.isRecommendFlag()) {
            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
                query.setSortIds(recommendInfo.getIds());
                result.put("recId", recommendInfo.getRecId());
                query.setPageNo(1);
            }
        }
        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
        List<GoodsInfo> infos = groupApiService.searchGroupByEsV6(query);
        ExtraInfoDTO extraInfo = future.get();
        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
        if (query.isTeamActQuery()) {
            // 球队活动页,数据按商家聚合重组
            buildInfoByMerchant(infos, result);
            infos = null;
        }
        result.put("merchants", extraInfo.getMerchants());
        groupApiService.getGroupRankV5(infos);
        return result.put("cardGroupInfos", infos).put("ref", "es");
    }

    @PostMapping(value = "/recommend")
    @ApiOperation("推荐有效拼团")
    public OutDTO getRecommend(@RequestBody InDto inDto) {
        if(Strings.isEmpty(inDto.getString("groupInfoId"))){
            return OutDTO.ok().put("cardGroupInfos", null);
        }
        Long groupInfoId = Long.parseLong(inDto.getString("groupInfoId"));
        List<GoodsInfo> infos = groupApiService.getRecommend2(groupInfoId, inDto.getUserId(), inDto.getPageNo(), inDto.getPageSize());
        return OutDTO.ok().put("cardGroupInfos", infos).put("ref", "es");
    }

    @ApiVersion(4.4)
    @PostMapping(value = "/recommend")
    @ApiOperation("推荐有效拼团")
    public OutDTO getRecommend3(@RequestBody InDto inDto) {
        if(Strings.isEmpty(inDto.getString("groupInfoId"))){
            return OutDTO.ok().put("cardGroupInfos", null);
        }
        Long groupInfoId = Long.parseLong(inDto.getString("groupInfoId"));
        CompletableFuture<List<GoodsInfo>> recommendFuture = groupApiService.getRecommend3(groupInfoId, inDto.getUserId());
        List<GoodsInfo> infos = recommendFuture.join();
        return OutDTO.ok().put("cardGroupInfos", infos).put("ref", "es");
    }

    private void buildInfoByMerchant(List<GoodsInfo> infos, OutDTO result) {
        if (CollectionUtils.isEmpty(infos)) {
            return;
        }
        Set<Long> merchantIds = infos.stream().map(GoodsInfo::getMerchantId).collect(Collectors.toSet());
        List<MerchantSortDTO> sortValues = merchantInfoService.getTeamSortVale(new ArrayList<>(merchantIds));
        // 按商家排序
        sortValues.sort(Comparator.comparing(MerchantSortDTO::isLivingFlag).reversed()
                .thenComparing((MerchantSortDTO dto) -> (double) dto.getSaleNum() / dto.getTotalNum(), Comparator.reverseOrder())
                .thenComparing(MerchantSortDTO::getId));

        // 按商家ID分组
        Map<Long, List<GoodsInfo>> groupedByMerchant = infos.stream().collect(Collectors.groupingBy(GoodsInfo::getMerchantId));

        List<MerchantGroupDTO> infoByMerchant = new ArrayList<>();
        List<BaseMerchantDTO> livingMerchant = new ArrayList<>();
        for (MerchantSortDTO sortValue : sortValues) {
            Integer merchantId = sortValue.getId();
            List<GoodsInfo> merchantGoods = groupedByMerchant.get(merchantId.longValue());
            if (merchantGoods != null) {
                merchantGoods.sort(Comparator.comparingDouble(goods -> -((double) goods.getRealSoldNum() / goods.getCopies())));
                GoodsInfo goodsInfo = merchantGoods.get(0);
                BaseMerchantDTO merchantInfo = new BaseMerchantDTO(sortValue.getId(), goodsInfo.getMerchantName(), goodsInfo.getAvatar());
                infoByMerchant.add(new MerchantGroupDTO(merchantInfo, merchantGoods));
                if (sortValue.isLivingFlag()) {
                    livingMerchant.add(merchantInfo);
                }
            }
        }
        result.put("infoByMerchant", infoByMerchant);
        result.put("livingMerchant", livingMerchant);
    }


    private Future<ExtraInfoDTO> getExtraInfoFuture(GroupQuery query) {
        String keyword = query.getKeyword();
        return pools.submit(() -> {
            ExtraInfoDTO extraInfo = new ExtraInfoDTO();
            if (StringUtils.isNotEmpty(keyword)) {
                extraInfo.setMerchants(merchantInfoService.selectMerchant(keyword));
            }
            // 球队活动页不查询广告
            if (!query.isTeamActQuery()) {
                extraInfo.setExtraInfos(adConfigService.selectAdBySearch(query));
            }
            return extraInfo;
        });
    }

    private List<GoodsInfo> buildInfoByAd(List<GoodsInfo> groups, List<SearchAdDTO> adList, InDto inDto, boolean recommendFlag) {
        log.debug("广告信息:{}", adList);
        if (CollectionUtils.isEmpty(adList)) {
            return groups;
        }
        List<GoodsInfo> infos = CollectionUtils.isEmpty(groups) ? new ArrayList<>() : groups;
        List<Long> adInfoIds = adList.stream().filter(ad -> Constants.ORDER_TYPE_GROUP.equals(ad.getType()))
                .map(SearchAdDTO::getRefId).collect(Collectors.toList());
        List<GoodsInfo> adInfos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(adInfoIds)) {
            adInfos = groupApiService.searchGroupByEs(new GroupQuery().setInfoIds(adInfoIds).setUserId(inDto.getUserId()));
        }
        int startNum = (inDto.getPageNo() - 1) * inDto.getPageSize() + 1;
        // 插入广告信息到 infos 中
        for (SearchAdDTO ad : adList) {
            GoodsInfo adInfo = convertToInfo(ad, adInfos);
            if (adInfo == null) {
                continue;
            }
            int index = ad.getAdNum() - startNum;
            boolean isUpdated = false;
            if (Constants.ORDER_TYPE_GROUP.equals(ad.getType())) {
                for (int i = 0; i < infos.size(); i++) {
                    GoodsInfo info = infos.get(i);
                    if (info.getId() == ad.getRefId().intValue()) {
                        info.setAdFlag(true);
                        info.setAdType(ad.getType());
                        if (i != index && index >= 0 && index < infos.size()) {
                            infos.remove(i);
                            infos.add(index, info);
                        }
                        isUpdated = true;
                        break;
                    }
                }
            }
            if (!isUpdated) {
                if (index >= 0 && index < infos.size()) {
                    infos.add(index, adInfo);
                } else {
                    infos.add(adInfo);
                }
            }
        }
        if (infos.size() > inDto.getPageSize()) {
            infos = infos.subList(0, inDto.getPageSize());
        }
        return infos;
    }

    private GoodsInfo convertToInfo(SearchAdDTO ad, List<GoodsInfo> adInfos) {
        if (Constants.ORDER_TYPE_GROUP.equals(ad.getType())) {
            return adInfos.stream().filter(info -> info.getId() == ad.getRefId().intValue())
                    .findFirst().map(info -> {
                        info.setAdFlag(true);
                        info.setAdType(ad.getType());
                        info.setRefAdId(ad.getId());
                        return info;
                    }).orElse(null);
        }
        return buildMerchantAdInfo(ad);
    }

    private static GoodsInfo buildMerchantAdInfo(SearchAdDTO ad) {
        GoodsInfo info = new GoodsInfo();
        info.setAdFlag(true);
        info.setAdType(ad.getType());
        info.setName(ad.getName());
        info.setCoverPicture(ad.getImgUrl());
        info.setLinkUrl(ad.getLinkUrl());
        info.setId(ad.getRefId().intValue());
        info.setMerchantId(ad.getRefId());
        info.setRefAdId(ad.getId());
        return info;
    }

    /**
     * 查询组团卡密
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "查询组团卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @PostMapping(value = "/goods")
    public OutDTO getGroupGoods(@RequestBody InDto inDto) {
        return groupApiService.searchGroupGoodsNew(inDto);
    }

    @ApiLog(title = "获取组队密队伍信息", businessType = BusinessType.SEARCH)
    @ResponseBody
    @PostMapping(value = "/guess")
    @ApiVersion(1.0)
    @ApiOperation("获取组队卡密队伍信息")
    public OutDTO getGroupGuessTeam(@RequestBody InDto inDto) {
        Object id = inDto.get("id");
        String type = inDto.getString("type");
        if (id == null || StringUtils.isEmpty(type)) {
            return OutDTO.error500("参数为空!");
        }
        String key = Constants.INFO_ONLY_TEAM_CACHE + type + id;
        Object cache = redisUtils.hget(Constants.INFO_ONLY_TEAM_CACHE, key);
        if (cache != null) {
            return OutDTO.ok().put("guessInfo", cache);
        }

        String sql;
        boolean isTeam = false;
        if (InfoActConfig.ACT_GUESS_TYPE_TEAM.equals(type)) {
            isTeam = true;
            sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupTeam");
        } else if (InfoActConfig.ACT_GUESS_TYPE_SET.equals(type)) {
            sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupBySet");
        } else if (InfoActConfig.ACT_GUESS_TYPE_PLAYER.equals(type)) {
            sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupByPlayer");
        } else {
            return OutDTO.error500("类型不存在!");
        }

        List<GroupTeamDTO> list = preparedSql.selectSomeField(sql, new GroupTeamDTO(), new Object[]{id});
        if (isTeam) {
            list.stream().filter(t -> StringUtils.isEmpty(t.getSimpleTeamName())).forEach(team -> {
                String simpleName = groupApiService.getTeamSimpleName(team.getTeam().trim());
                team.setSimpleTeamName(simpleName);
            });
        }
        redisUtils.hset(Constants.INFO_ONLY_TEAM_CACHE, key, list, 7200);
        return OutDTO.ok().put("guessInfo", list);
    }

    @ApiLog(title = "获取组队密队伍信息,新接口,替换之前接口", businessType = BusinessType.SEARCH)
    @ResponseBody
    @RequestMapping(value = "/v3/team", method = RequestMethod.POST)
    @ApiVersion(2.0)
    @ApiOperation("获取组队卡密队伍信息")
    public OutDTO getGroupTeamV3(@RequestBody InDto inDto) {
        Integer id = (Integer) inDto.get("id");
        Boolean onlyTeam = (Boolean) inDto.get("onlyTeam");
        Boolean cacheFlag = (Boolean) inDto.get("cacheFlag");
        boolean isUserCache = cacheFlag == null || cacheFlag;
        Map<String, List<GroupTeamDTO>> list = buildSelectTeamsNew(id, onlyTeam, isUserCache);
        return OutDTO.ok().put("groupTeam", list);
    }
    @ApiLog(title = "获取组队密队伍信息,【支持买队剩余随机】", businessType = BusinessType.SEARCH)
    @ResponseBody
    @RequestMapping(value = "/v4/buyTeam", method = RequestMethod.POST)
    @ApiVersion(2.0)
    @ApiOperation("获取组队卡密队伍信息【支持买队剩余随机】")
    public OutDTO getGroupTeamV4(@RequestBody InDto inDto) {
        Integer id = (Integer) inDto.get("id");
        Boolean onlyTeam = (Boolean) inDto.get("onlyTeam");
        Boolean cacheFlag = (Boolean) inDto.get("cacheFlag");
        boolean isUserCache = cacheFlag == null || cacheFlag;
        Map<String, List<GroupTeamDTO>> list = buildSelectTeamsNewV2(id, onlyTeam, isUserCache);
        return OutDTO.ok().put("groupTeam", list);
    }

    /**
     * 支持查询
     * @param infoId
     * @param isOnlyTeam
     * @param isUserCache
     * @return
     */
    private Map<String, List<GroupTeamDTO>> buildSelectTeamsNewV2(Integer infoId, boolean isOnlyTeam, boolean isUserCache) {
        GroupInfo groupInfo = groupApiService.getGroupInfoById(infoId);
        Map<String, List<GroupTeamDTO>> list;
        if (Constants.INFO_TYPE_TEAM_TO_RANDOM.equals(groupInfo.getChangeType())) {
//            return groupApiService.getGroupTeamToRandom(infoId);
            return groupApiService.getGroupTeamToRandomV2(infoId,groupInfo.getType());
        }
        //如果买队 查询剩余的 卡密列表和库存
        if (Constants.INFO_TYPE_BUY_TEAM.equals(groupInfo.getType())) {
            List<SimpleGroupGoodsDTO> goods = groupApiService.selectedGoodsByInfoIdV2(infoId.longValue(), groupInfo.getStatus() >= 201);
            log.debug("查询剩余的卡密列表和库存:{}", goods);
            Map<String, List<SimpleGroupGoodsDTO>> collect = goods.stream()
                                                                  .collect(Collectors.groupingBy(SimpleGroupGoodsDTO::getTeam));
            list = collect.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
                                                                                                         .stream()
                                                                                                         .map(goodsDto -> {
                                                                                                             GroupTeamDTO team =new GroupTeamDTO();
                                                                                                             team.setPlayerName(goodsDto.getPlayerName());
                                                                                                             team.setTeam(goodsDto.getTeam());
                                                                                                             team.setSimpleTeamName(goodsDto.getSimpleTeamName());
                                                                                                             team.setPrice(goodsDto.getPrice());
                                                                                                             team.setTeamId(goodsDto.getTeamId());
                                                                                                             team.setCopies(1);//买队默认 为1份
                                                                                                             team.setConference(goodsDto.getConference());
                                                                                                             return team;
                                                                                                         }).collect(Collectors.toList())));

            return list;
        }
        String key = isOnlyTeam ? Constants.INFO_ONLY_TEAM_CACHE + infoId : Constants.INFO_SELECT_TEAM_CACHE + infoId;
        Object cache = RedisTools.getRedisUtils().hget(key, infoId.toString());
        if (cache == null || !isUserCache) {
            List<SimpleGroupGoodsDTO> goods = groupApiService.selectedGoodsByInfoId(infoId.longValue(), groupInfo.getStatus() >= 201);
            list = buildGroupTeams(groupInfo, isOnlyTeam, goods);
            RedisTools.getRedisUtils().hset(key, infoId.toString(), list, 7200);
            if (!isOnlyTeam) {
                RedisTools.getRedisUtils().expire(key, 1800);
            }
        } else {
            list = (Map<String, List<GroupTeamDTO>>) cache;
        }
        return list;
    }

    private Map<String, List<GroupTeamDTO>> buildSelectTeamsNew(Integer infoId, boolean isOnlyTeam, boolean isUserCache) {
        GroupInfo groupInfo = groupApiService.getGroupInfoById(infoId);
        if (Constants.INFO_TYPE_TEAM_TO_RANDOM.equals(groupInfo.getChangeType())) {
            return groupApiService.getGroupTeamToRandom(infoId);
        }
        String key = isOnlyTeam ? Constants.INFO_ONLY_TEAM_CACHE + infoId : Constants.INFO_SELECT_TEAM_CACHE + infoId;
        Object cache = RedisTools.getRedisUtils().hget(key, infoId.toString());
        Map<String, List<GroupTeamDTO>> list;
        if (cache == null || !isUserCache) {
            List<SimpleGroupGoodsDTO> goods = groupApiService.selectedGoodsByInfoId(infoId.longValue(), groupInfo.getStatus() >= 201);
            list = buildGroupTeams(groupInfo, isOnlyTeam, goods);
            RedisTools.getRedisUtils().hset(key, infoId.toString(), list, 7200);
            if (!isOnlyTeam) {
                RedisTools.getRedisUtils().expire(key, 1800);
            }
        } else {
            list = (Map<String, List<GroupTeamDTO>>) cache;
        }
        return list;
    }

    private Map<String, List<GroupTeamDTO>> buildGroupTeams(GroupInfo groupInfo, boolean isOnlyTeam, List<SimpleGroupGoodsDTO> goods) {
        boolean isArea = Constants.INFO_SUB_TYPE_AREA_RANDOM.equals(groupInfo.getSubType());
        Map<String, Integer> numByTeamOrConference = new HashMap<>();
        if (!isOnlyTeam) {
            numByTeamOrConference = getSoldNumByType(groupInfo.getId().intValue(), isArea);
        }

        Map<String, List<SimpleGroupGoodsDTO>> goodsByTeamOrConference;
        if (isArea) {
            goodsByTeamOrConference = goods.stream().collect(Collectors.groupingBy(SimpleGroupGoodsDTO::getConference));
        } else {
            goodsByTeamOrConference = goods.stream().collect(Collectors.groupingBy(SimpleGroupGoodsDTO::getTeam));
        }

        Map<String, List<GroupTeamDTO>> list;
        List<GroupTeamDTO> groupTeams = new ArrayList<>();
        Set<String> teams = goodsByTeamOrConference.keySet();
        for (String team : teams) {
            List<SimpleGroupGoodsDTO> goodsByTeam = goodsByTeamOrConference.get(team);
            SimpleGroupGoodsDTO simpleGroupGoods = goodsByTeam.get(0);
            GroupTeamDTO groupTeam = new GroupTeamDTO();
            groupTeam.setConference(simpleGroupGoods.getConference());
            groupTeam.setPrice(simpleGroupGoods.getPrice());
            groupTeam.setCopies(goodsByTeam.size());

            if (!isArea) {
                groupTeam.setZnTeam(simpleGroupGoods.getZnTeam());
                groupTeam.setTeamId(simpleGroupGoods.getTeamId());
                groupTeam.setTeam(team);
                GroupTeamDTO simpleDto = groupApiService.getSimpleTeamDTO(team.trim());
                groupTeam.setSimpleTeamName(simpleDto.getSimpleTeamName());
                groupTeam.setRemark(simpleDto.getRemark());
            }

            if (!isOnlyTeam) {
                Integer num = numByTeamOrConference.get(isArea ? groupTeam.getConference() : groupTeam.getTeamId().toString());
                groupTeam.setSoldCopies(num != null ? num : 0);
            }
            groupTeams.add(groupTeam);
        }
        list = groupTeams.stream().collect(Collectors.groupingBy(GroupTeamDTO::getConference));
        return list;
    }

    private Map<String, Integer> getSoldNumByType(Integer infoId, Boolean isArea) {
        Map<String, Integer> numByTeamOrConference;
        if (isArea) {
            numByTeamOrConference = groupApiService.getGroupLockNumByConference(infoId);
        } else {
            numByTeamOrConference = groupApiService.getGroupLockNumByTeamId(infoId);
        }
        return numByTeamOrConference;
    }


    private Map<String, List<GroupTeamDTO>> getSelectTeams(Object id, Object onlyTeam) {
        String key;
        boolean isOnlyTeam = onlyTeam != null && (Boolean) onlyTeam;
        if (isOnlyTeam) {
            key = Constants.INFO_ONLY_TEAM_CACHE + id;
        } else {
            key = Constants.INFO_SELECT_TEAM_CACHE + id;
        }
        Object cache = RedisTools.getRedisUtils().hget(key, id.toString());
        Map<String, List<GroupTeamDTO>> list;
        if (cache == null) {
            String sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupTeam");
            List<GroupTeamDTO> groupTeamDTOS = preparedSql.selectSomeField(sql, new GroupTeamDTO(), new Object[]{id});
            groupTeamDTOS.forEach(team -> setCountAndSimpleName(team, id, onlyTeam));
            list = groupTeamDTOS.stream().collect(Collectors.groupingBy(GroupTeamDTO::getConference));
            RedisTools.getRedisUtils().hset(key, id.toString(), list, 7200);
            if (!isOnlyTeam) {
                RedisTools.getRedisUtils().expire(key, 60);
            }
        } else {
            list = (Map<String, List<GroupTeamDTO>>) cache;
        }
        return list;
    }

    private void setCountAndSimpleName(GroupTeamDTO team, Object id, Object onlyTeam) {
        if (onlyTeam == null || !(Boolean) onlyTeam) {
            String sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupTeamCount");
            List<TeamCountDTO> countDTOS = preparedSql.selectSomeField(sql, new TeamCountDTO(), new Object[]{id, team.getTeamId()});
            TeamCountDTO teamCountDTO = countDTOS.get(0);
            Integer unPayOrderCount = orderListMapper.selectUnPayTeamCount((Integer) id, team.getTeamId());
            team.setCopies(teamCountDTO.getCopies());
            team.setSoldCopies(teamCountDTO.getSoldCopies() + unPayOrderCount);
        }

        if (StringUtils.isEmpty(team.getSimpleTeamName())) {
            String simpleName = groupApiService.getTeamSimpleName(team.getTeam().trim());
            team.setSimpleTeamName(simpleName);
        }

    }

    /**
     * 选队随机玩法从选队改为随机
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "选队随机玩法从选队改为随机", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @RequestMapping(value = "/changeInfoType", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
    public OutDTO changeInfoType(@RequestBody InDto inDto) {
        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
        Integer groupInfoId = (Integer) inDto.get("groupInfoId");
        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectSoldCardGroupInfoById(groupInfoId.longValue());
        if (cardGroupInfo == null || !Constants.INFO_TYPE_SELECT_TEAM.equals(cardGroupInfo.getType())) {
            return OutDTO.error500("组团信息不符合要求!");
        }
        List<SysDictData> changeType = dictDataService.getByTypeAndStatus(Constants.TEAM_CHANGE_RATE, Constants.ONE);
        int rate = 50;
        if (!changeType.isEmpty()) {
            if (changeType.size() == 1) {
                rate = Integer.parseInt(changeType.get(0).getDictValue());
            } else {
                List<SysDictData> rateValue = changeType.stream().filter(t -> appUserInfoDto.getRolecode().equals(t.getDictLabel())).collect(Collectors.toList());
                rate = Integer.parseInt(rateValue.get(0).getDictValue());
            }
        }
        if (cardGroupInfo.getRealSoldNum() * 100 / cardGroupInfo.getCopies() < rate) {
            return OutDTO.error500("售出比例不足,无法修改!");
        }

        String lockKey = "BUY_LOCK_" + groupInfoId;
        boolean isLock;
        try {
            isLock = redisUtils.tryLock(lockKey, TimeUnit.SECONDS, 15L);
            if (isLock) {
                // 查询未付款的用户数（订单）
                if (orderInfoService.checkIsUnPayOrder(groupInfoId)) {
                    redisUtils.unlock(lockKey);
                    return OutDTO.error(500, "存在未支付订单,玩法不可修改,请稍后再试!");
                }
                CardGroupInfo update = new CardGroupInfo();
                update.setId(cardGroupInfo.getId());
                update.setChangeType(Constants.INFO_TYPE_TEAM_TO_RANDOM);
                BigDecimal price = cardGroupInfoService.calculateUnitPrice(groupInfoId);
                if (StringUtils.isNotEmpty(cardGroupInfo.getPointType()) && cardGroupInfo.getPointType().startsWith(Constants.POINT_TYPE_MERCHANT_ACT_PRE)) {
                    price = new BigDecimal(price.intValue() + "");
                }
                update.setUnitPrice(price);
                cardGroupInfoService.updateCardGroupInfo(update);
                log.info("选队转随机,拼团code:{},价格:{}", cardGroupInfo.getCode(), price);
                cardGroupInfoService.markGoodsStatus(cardGroupInfo.getId());
                Map<String, List<GroupTeamDTO>> selectTeams = getSelectTeams(groupInfoId, false);
                redisUtils.hset(Constants.INFO_TEAM_TO_RANDOM_CACHE, groupInfoId.toString(), selectTeams);
                redisUtils.del("order_group_cache:" + groupInfoId);
                redisUtils.unlock(lockKey);
                return OutDTO.ok();
            }
        } catch (ServiceException e) {
            log.error("修改组队玩法异常,id:{}", groupInfoId, e);
            return OutDTO.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("修改组队玩法异常,id:{}", groupInfoId, e);
        } finally {
            try {
                redisUtils.unlock(lockKey);
            } catch (Exception e) {
                log.error("锁释放异常:", e);
            }
        }
        return OutDTO.error500("修改组队玩法失败");
    }


    /**
     * 选队随机/买队玩法 改为剩余随机
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "选队随机/买队玩法 改为剩余随机", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @RequestMapping(value = "/v2/changeInfoType", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
    public OutDTO changeInfoTypeV2(@RequestBody InDto inDto) {
        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
        Integer groupInfoId = (Integer) inDto.get("groupInfoId");
        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectSoldCardGroupInfoById(groupInfoId.longValue());
        if (cardGroupInfo == null || !Constants.CAN_CHANGE_RATE.contains(cardGroupInfo.getType())) {
            return OutDTO.error500("组团信息不符合要求!");
        }
        List<SysDictData> changeType = dictDataService.getByTypeAndStatus(Constants.BUY_TEAM_CHANGE_RATE, Constants.ONE);
        int rate = 50;
        if (!changeType.isEmpty()) {
            if (changeType.size() == 1) {
                rate = Integer.parseInt(changeType.get(0).getDictValue());
            } else {
                List<SysDictData> rateValue = changeType.stream().filter(t -> appUserInfoDto.getRolecode().equals(t.getDictLabel())).collect(Collectors.toList());
                rate = Integer.parseInt(rateValue.get(0).getDictValue());
            }
        }
        if (cardGroupInfo.getRealSoldNum() * 100 / cardGroupInfo.getCopies() < rate) {
            return OutDTO.error500("售出比例不足,无法修改!");
        }

        String lockKey = "BUY_LOCK_" + groupInfoId;
        boolean isLock;
        try {
            isLock = redisUtils.tryLock(lockKey, TimeUnit.SECONDS, 15L);
            if (isLock) {
                // 查询未付款的用户数（订单）
                if (orderInfoService.checkIsUnPayOrder(groupInfoId)) {
                    redisUtils.unlock(lockKey);
                    return OutDTO.error(500, "存在未支付订单,玩法不可修改,请稍后再试!");
                }
                CardGroupInfo update = new CardGroupInfo();
                update.setId(cardGroupInfo.getId());
                update.setChangeType(Constants.INFO_TYPE_TEAM_TO_RANDOM);
                BigDecimal price = cardGroupInfoService.calculateUnitPrice(groupInfoId);
                if (StringUtils.isNotEmpty(cardGroupInfo.getPointType()) && cardGroupInfo.getPointType().startsWith(Constants.POINT_TYPE_MERCHANT_ACT_PRE)) {
                    price = new BigDecimal(price.intValue() + "");
                }
                update.setUnitPrice(price);
                cardGroupInfoService.updateCardGroupInfo(update);
                log.info("选队随机/买队玩法 改为剩余随机,拼团code:{},玩法:{},价格:{}", cardGroupInfo.getCode(),cardGroupInfo.getType(), price);
                cardGroupInfoService.markGoodsStatus(cardGroupInfo.getId());
                boolean onlyTeam = cardGroupInfo.getType().equals(Constants.INFO_TYPE_BUY_TEAM);
                Map<String, List<GroupTeamDTO>> selectTeams;
                //如果是买队转随机 查询已转随机的卡密
                if (onlyTeam) {
                    selectTeams = getBuyTeamToChange(groupInfoId);
                } else {
                    selectTeams = getSelectTeams(groupInfoId, onlyTeam);
                }
                redisUtils.hset(Constants.INFO_TEAM_TO_RANDOM_CACHE, groupInfoId.toString(), selectTeams);
                redisUtils.del("order_group_cache:" + groupInfoId);
                redisUtils.unlock(lockKey);
                return OutDTO.ok();
            }
        } catch (ServiceException e) {
            log.error("修改组队玩法异常,id:{}", groupInfoId, e);
            return OutDTO.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("修改组队玩法异常,id:{}", groupInfoId, e);
        } finally {
            try {
                redisUtils.unlock(lockKey);
            } catch (Exception e) {
                log.error("锁释放异常:", e);
            }
        }
        return OutDTO.error500("修改组队玩法失败");
    }

    /**
     * 买队转随机 查询已转随机的卡密
     * @param groupInfoId
     * @return
     */
    private Map<String, List<GroupTeamDTO>> getBuyTeamToChange(Integer groupInfoId) {
        Map<String, List<GroupTeamDTO>> selectTeams;
        String sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupChangeTeam");
        List<GroupTeamDTO> groupTeamDTOS = preparedSql.selectSomeField(sql, new GroupTeamDTO(), new Object[]{groupInfoId});
        groupTeamDTOS.forEach(team -> {
            String simpleName = groupApiService.getTeamSimpleName(team.getTeam().trim());
            team.setSimpleTeamName(simpleName);
        });
        selectTeams = groupTeamDTOS.stream().collect(Collectors.groupingBy(GroupTeamDTO::getConference));
        return selectTeams;
    }

    /**
     * 获取组团订单金额信息
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "获取组团订单金额信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @RequestMapping(value = "/getGroupAmount", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_LIVING, UserType.USER_ROLE_DELIVERY, UserType.USER_ROLE_PUBLICITY})
    public OutDTO getGroupAmount(@RequestBody InDto inDto) {
        UserInfo user = UserUtils.getSimpleUserInfo();
        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
        Integer groupInfoId = inDto.getIntegerParam("groupInfoId");
        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectCardGroupInfoById(groupInfoId.longValue());
        if (cardGroupInfo == null || user.getMerchantId() != cardGroupInfo.getMerchantId().intValue()) {
            return OutDTO.error500("组团信息不符合要求!");
        }
        return cardGroupInfoService.getGroupAmount(cardGroupInfo);
    }


    /**
     * 卡密详情
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "卡密详情", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @RequestMapping(value = "/getGoodsDetail", method = RequestMethod.POST)
    public OutDTO getGoodsDetail(@RequestBody InDto inDto) {
        Object id = inDto.get("id");
        if (id == null) {
            return OutDTO.error500("id为空!");
        }
        CardGroupGoods goods = new CardGroupGoods();
        goods.setId(Long.valueOf(id.toString()));
        CardGroupGoods groupGoods = suidRich.selectOne(goods);
        return OutDTO.ok().put("groupGoods", groupGoods);
    }

    /**
     * 获取活动卡密
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "获取活动卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @RequestMapping(value = "/act/goods", method = RequestMethod.POST)
    public OutDTO getActGoods(@RequestBody InDto inDto) {
        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
        if (inDto.get("id") == null) {
            return OutDTO.error500("参数为空");
        }
        List<ActGoods> goodsList = getActGoods(Long.valueOf(inDto.getString("id")), userInfo.getId().longValue());
        return OutDTO.ok().put("goods", goodsList);
    }

    private List<ActGoods> getActGoods(Long infoId, Long userId) {
        ActGoods goods = new ActGoods();
        goods.setGroupInfoId(infoId);
        goods.setUserId(userId);
        goods.setActStatus(0);
        Condition condition = new ConditionImpl();
        condition.op("actId", Op.gt, 0);
        List<ActGoods> goodsList = suidRich.select(goods, condition);
        return goodsList;
    }

    /**
     * 获取活动卡密
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "获取活动卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @RequestMapping(value = "/act/goods/exchange", method = RequestMethod.POST)
    public OutDTO exchangeActGoods(@RequestBody InDto inDto) {
        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
        if (inDto.get("id") == null) {
            return OutDTO.error500("参数为空");
        }
        Long infoId = Long.valueOf(inDto.getString("id"));
        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectCardGroupInfoById(infoId);
        if (!Constants.GROUP_FULL_STATUS.contains(cardGroupInfo.getStatus().intValue())) {
            return OutDTO.error500("组团尚未完成,请组齐后再兑换");
        }
        if (StringUtils.isNotEmpty(cardGroupInfo.getHotTypeConfig())) {
            JSONObject jsonObject = JSONObject.parseObject(cardGroupInfo.getHotTypeConfig());
            String endTime = jsonObject.getString("endTime");
            Date date = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime);
            if (date.before(new Date())) {
                return OutDTO.error500("已过奖品兑换时间！");
            }
        }
        List<ActGoods> goodsList = getActGoods(infoId, userInfo.getId().longValue());
        orderInfoService.exchangeActGoods(goodsList, userInfo);
        return OutDTO.ok();
    }


    /**
     * 查询组团订单用户信息
     *
     * @param inDto
     * @return
     */
    @ApiLog(title = "查询组团订单用户信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @RequestMapping(value = "/order/user", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_LIVING, UserType.USER_ROLE_DELIVERY, UserType.USER_ROLE_PUBLICITY})
    public OutDTO getGroupOrderUser(@RequestBody InDto inDto) {
        GroupOrderUserDTO orderUserDTO = new GroupOrderUserDTO();
        orderUserDTO.setGroupInfoId(Integer.valueOf(inDto.getString("ids")));
        String statusStr = inDto.getString("status");
        List<Integer> statusList;
        boolean isHide = false;
        if (StringUtils.isNotEmpty(statusStr)) {
            statusList = Arrays.stream(statusStr.split(",")).map(s -> Integer.valueOf(s)).collect(Collectors.toList());
            if (statusList.contains(201)) {
                isHide = true;
            }
        } else {
            statusList = Arrays.asList(new Integer[]{101});
        }


        // orderUserDTO.setStatus(101);
        Condition condition = new ConditionImpl();
        condition.op("status", Op.in, statusList);
        condition.op("orderSubType", Op.eq, null);
        condition.orderBy("id", OrderType.DESC);
        condition.start((inDto.getPageNo() - 1) * inDto.getPageSize()).size(inDto.getPageSize());
        List<GroupOrderUserDTO> groupUserOrderDtos = suidRich.select(orderUserDTO, condition);
        if (isHide) {
            groupUserOrderDtos.forEach(g -> {
                g.setShippingAddressLinkname(null);
                g.setShippingAddress(null);
                g.setShippingAddressPhone(null);
            });
        }
        return OutDTO.ok().put("groupUserOrderDtos", groupUserOrderDtos);
    }

    /**
     * 查询组团订单用户信息
     *
     * @param inDto
     * @return
     */
    @ApiVersion(3.9)
    @ApiLog(title = "查询组团订单用户信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @RequestMapping(value = "/order/user", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_LIVING, UserType.USER_ROLE_DELIVERY, UserType.USER_ROLE_PUBLICITY})
    public OutDTO getGroupOrderUserV2(@RequestBody InDto inDto) {
        String statusStr = inDto.getString("status");
        //isMerchantOpen 空-全部 0-否商家代搓 1-是商家代搓
        Integer isMerchantOpen =-1;
        if(inDto.existKeyString("isMerchantOpen") && inDto.getIntegerParam("isMerchantOpen")!=null){
            isMerchantOpen = inDto.getIntegerParam("isMerchantOpen");
        }
        List<Integer> statusList;
        boolean isHide = false;
        if (StringUtils.isNotEmpty(statusStr)) {
            statusList = Arrays.stream(statusStr.split(",")).map(s -> Integer.valueOf(s)).collect(Collectors.toList());
            if (statusList.contains(201)) {
                isHide = true;
            }
        } else {
            statusList = Arrays.asList(new Integer[]{101});
        }
        List<GroupOrderUserDTO> groupUserOrderDtos;
        if (isMerchantOpen >= 0) {
            // 使用带商户开放状态筛选的查询
            groupUserOrderDtos = groupApiService.getGroupOrderUserWithMerchantOpen(Long.valueOf(inDto.getString("ids")), statusList,isMerchantOpen);
        } else {
            // 使用普通查询
            groupUserOrderDtos = groupApiService.getGroupOrderUserV2(Long.valueOf(inDto.getString("ids")), statusList);
        }

        groupUserOrderDtos.forEach(g -> {
            //已支付的查询是否已开卡密
            if(g.getStatus() != 206 && g.getStatus() != 301){
                //查询未解锁的数据
                int unLockCount = groupApiService.getCountByLockstatus(g.getUserId().intValue(), g.getId().intValue(), 0);
                g.setUnLockStatus(unLockCount == 0 ? 1 : 0);
            }else{
                g.setUnLockStatus(1);
            }
        });
        if (isHide) {
            groupUserOrderDtos.forEach(g -> {
                g.setShippingAddressLinkname(null);
                g.setShippingAddress(null);
                g.setShippingAddressPhone(null);
            });
        }
        return OutDTO.ok().put("groupUserOrderDtos", groupUserOrderDtos);
    }


    @ApiLog(title = "上传生态购code", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
    @ResponseBody
    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁!")
    @RequestMapping(value = "/info/code/save", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_OPERATE_USER})
    @ApiVersion(2.0)
    public OutDTO saveSaleCode(@RequestBody InDto inDto) {
        ActSaleCode saleCode = inDto.buildParam(new ActSaleCode());
        if (StringUtils.isEmpty(saleCode.getCode()) || saleCode.getMerchantId() == null || saleCode.getPaniniBaseId() == null) {
            return OutDTO.error500("参数缺失!");
        }
        if (!CollectionUtils.isEmpty(suidRich.select(new ActSaleCode(saleCode.getCode()).setStatus(0)))) {
            return OutDTO.error500("该code已存在!");
        }
        saleCode.setCreateTime(new Date());
        suidRich.insert(saleCode);
        return OutDTO.ok();
    }

    @ApiLog(title = "核销code", businessType = BusinessType.SEARCH)
    @ResponseBody
    @ApiVersion(2.0)
    @PostMapping(value = "/verify/info/code")
    @ApiOperation("核销code")
    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
    public OutDTO verifyInfoCode(@RequestBody InDto inDto) {
        SaleCodeRecord codeRecord = inDto.buildParam(new SaleCodeRecord());
        SaleCodeRecord existRecord = checkCodeRecord(codeRecord);
        SaleCodeRecord editRecord = new SaleCodeRecord().setId(existRecord.getId()).setStatus(1)
                .setImg(codeRecord.getImg()).setVerifyTime(new Date()).setRemark(codeRecord.getRemark());
        suidRich.update(editRecord);
        return OutDTO.ok();
    }

    private SaleCodeRecord checkCodeRecord(SaleCodeRecord codeRecord) {
        UserInfo user = UserUtils.getSimpleUserInfo(true);
        if (user == null || user.getMerchantId() == null) {
            throw new ServiceException("权限不足!");
        }
        if (StringUtils.isEmpty(codeRecord.getCode()) || StringUtils.isEmpty(codeRecord.getImg()) || codeRecord.getRefId() == null) {
            throw new ServiceException("参数缺失!");
        }
        GroupInfo groupInfo = groupApiService.getGroupInfoById(codeRecord.getRefId());
        if (groupInfo == null || groupInfo.getMerchantId() != user.getMerchantId().longValue() || groupInfo.getStatus() != 203) {
            throw new ServiceException("被核销拼团信息异常!");
        }
        SaleCodeRecord cond = new SaleCodeRecord().setCode(codeRecord.getCode()).setStatus(0).setRefId(codeRecord.getRefId()).setType(Constants.ORDER_TYPE_GROUP);
        SaleCodeRecord existRecord = suidRich.selectOne(cond);
        if (existRecord == null) {
            throw new ServiceException("核销码记录不存在!");
        }
        return existRecord;
    }

    @ResponseBody
    @RequestMapping(value = "/info/code/select", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_OPERATE_USER})
    public OutDTO selectSaleCode(@Validated(Select.class) @RequestBody ActSaleCode saleCode) {
        return OutDTO.ok().put("codes", suidRich.select(saleCode));
    }


    /**
     * 上传生态购code
     * @param saleCode
     * @return
     */
    @ResponseBody
    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁!")
    @RequestMapping(value = "/v2/info/code/save", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_OPERATE_USER,UserType.USER_ROLE_MERCHANT_OPERATE_CODE, UserType.USER_ROLE_ECOLOGICAL_SHOPPING})
    @ApiVersion(3.2)
    public OutDTO saveSaleCodeV2(@Validated(Insert.class) @RequestBody ActSaleCode saleCode) {
        if (ActConstans.CARTON.equals(saleCode.getBoxType()) && saleCode.getBoxNum() > 1) {
            return OutDTO.error500("箱数量不能超过1!");
        }
        if (!CollectionUtils.isEmpty(suidRich.select(new ActSaleCode(saleCode.getCode()).setStatus(0)))) {
            return OutDTO.error500("该code已存在!");
        }
        //start 2024年11月28日 校验生态购验证码是否存在，且是否有效
        PyErpRandomCode pyErpRandomCode = pyErpRandomCodeService.checkPyErpRandomCode(saleCode);
        //end
        CardGroupOrderInfo orderInfo = checkBindOrder(saleCode,pyErpRandomCode);
//        CardGroupOrderInfo orderInfo = checkBindOrder(saleCode);
        int totalCount = getTotalCount(saleCode.getOrderId(), saleCode.getBoxType());
        int totalNum = totalCount + saleCode.getBoxNum();
        AppAssert.isTrue(totalNum <= orderInfo.getPurchaseCount(), "超出订单最大数量!");
        boolean isOver = totalNum == orderInfo.getPurchaseCount();
        saleCode.setCreateTime(new Date());
        //设置panini listId ,拼团listId ,setsVersion , 商家id
        saleCode.setPaniniBaseId(Math.toIntExact(pyErpRandomCode.getPaniniId()));
        saleCode.setListId(pyErpRandomCode.getListId());
        saleCode.setSetsVersion(pyErpRandomCode.getSetsVersion());
        saleCode.setMerchantId(saleCode.getMerchantId());
        saleCode.setCode(pyErpRandomCode.getRandomCodePri());
        saleCode.setCodePub(pyErpRandomCode.getRandomCodePub());
        int insert = suidRich.insert(saleCode);
        //如果新增成功， 则更新为 已出库 2024年11月28日
        if(insert > 0){
            //如果新增成功， 则更新为 已出库
            pyErpRandomCode.setOrderId(saleCode.getOrderId());
            pyErpRandomCode.setMerchantId(Long.valueOf(saleCode.getMerchantId()));
            pyErpRandomCode.setProp2(saleCode.getRemark());
            pyErpRandomCodeService.updatePyErpRandomCode(pyErpRandomCode);
        }
        //end
        if (isOver) {
            completeSaleCodeOrder(saleCode);
        }
        return OutDTO.ok().put("completed", isOver).put("totalNum", totalNum);
    }



    @ResponseBody
    @RequestMapping(value = "/count/order/code", method = RequestMethod.POST)
    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_OPERATE_USER,UserType.USER_ROLE_MERCHANT_OPERATE_CODE})
    @ApiVersion(3.2)
    public OutDTO countOrderSaleCode(@RequestBody ActSaleCode saleCode) {
        int totalCount = getTotalCount(saleCode.getOrderId(), saleCode.getBoxType());
        return OutDTO.ok().put("totalNum", totalCount);
    }

    /**
     * 添加判断订单是否是同一产品
     * @param saleCode
     * @param pyErpRandomCode
     * @return
     */
    private CardGroupOrderInfo checkBindOrder(ActSaleCode saleCode,PyErpRandomCode pyErpRandomCode) {
        //修改为对象返回 基础库id， 系列版本，2024年11月28日
        ChecklistConfigDto checklistConfigDto = orderInfoService.getOneOrderSkuUnit(saleCode.getOrderId());
        //判断是否是同一产品 根据基础库id 和版本
        AppAssert.isTrue(Objects.equals(pyErpRandomCode.getPaniniId(),checklistConfigDto.getPaniniListId())
                                 && Objects.equals(pyErpRandomCode.getSetsVersion(),checklistConfigDto.getSetsVersion()), "上传产品和商品产品不一致!");
        //end
        CardGroupOrderInfo orderInfo = orderInfoService.selectCardGroupOrderInfoById(saleCode.getOrderId());
        AppAssert.isTrue(orderInfo.getServeStatus() == 200, "订单未处于待核销状态!");
        AppAssert.isTrue(saleCode.getBoxNum() <= orderInfo.getPurchaseCount(), "超出订单最大数量!");
        AppAssert.isTrue(saleCode.getBoxType().equals(GroupActService.getSpecConfigType(checklistConfigDto.getUnit())), "上传规格和商品规格不一致!");
        return orderInfo;
    }

    private void completeSaleCodeOrder(ActSaleCode saleCode) {
        CardGroupOrderInfo order = new CardGroupOrderInfo();
        order.setId(saleCode.getOrderId());
        order.setServeStatus(210);
        orderInfoService.updateCardGroupOrderInfo(order);
    }

    private int getTotalCount(Long orderId, String boxType) {
        ActSaleCode cond = new ActSaleCode().setStatus(0).setOrderId(orderId).setBoxType(boxType);
        String s = suidRich.selectWithFun(cond, FunctionType.SUM, "boxNum");
        return StringUtils.isEmpty(s) ? 0 : Integer.parseInt(s);
    }

    @ResponseBody
    @ApiVersion(3.2)
    @PostMapping(value = "/v2/verify/info/code")
    @ApiOperation("新版核销code")
    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
    public OutDTO verifyInfoCodeV2(@Validated @RequestBody CheckSaleCodeDTO checkSaleCode) {
        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
        AppAssert.notNull(userInfo, "权限不足!");
        checkSaleCode.setMerchantId(userInfo.getMerchantId());
        //添加验证商家是否已经收货
        PyErpRandomCodeReq pyErpRandomCode = new PyErpRandomCodeReq();
        pyErpRandomCode.setCode(checkSaleCode.getCode());
        PyErpRandomCode erpRandomCode = pyErpRandomCodeService.getPyErpRandomCode(pyErpRandomCode);
        if(!Objects.equals(erpRandomCode.getStatus(),PyRandomCodeEnums.MER_IN_STOCK.getCode())){
            return OutDTO.error500("该核销码处于【"+PyRandomCodeEnums.getMsg(erpRandomCode.getStatus())+"】!");
        }
        ActSaleCode saleCode = groupActService.checkSaleCode(checkSaleCode.getCode(), checkSaleCode.getMerchantId());
        GroupSaleCodeDTO saleCodeConfig = groupApiService.checkGroup(checkSaleCode.getGroupInfoId(), saleCode.getSetsVersion());
        checkSaleCode.setSaleCodeConfig(saleCodeConfig);
        groupActService.checkUsedGroupSaleCode(checkSaleCode, saleCode);
        boolean livingOpenAble = groupActService.checkGroupSaleCodeCount(checkSaleCode.getGroupInfoId(), checkSaleCode.getMerchantId(), saleCodeConfig);
        return OutDTO.ok().put("livingOpenAble", livingOpenAble);
    }

    /**
     * 商家签收生态购订单
     *
     */
    @ResponseBody
    @ApiVersion(1.0)
    @PostMapping(value = "/merchant/sign/order")
    @ApiOperation("商家签收生态购订单")
    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public OutDTO merchantSignOrder(@Validated(Update.class) @RequestBody RandomCodeMerInReq req) {
        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
        AppAssert.notNull(userInfo, "权限不足!");
        //查询订单信息
        CardGroupOrderInfo orderInfo = orderInfoService.selectCardGroupOrderInfoById(req.getOrderId());
        AppAssert.notNull(orderInfo, "订单不存在!");
        //查询订单所属商家
        //根据userId 查询商家
        MerchantInfo merchantInfo = merchantApiService.getMerchantByAppUserId(Math.toIntExact(orderInfo.getUserId()));
        AppAssert.notNull(merchantInfo, "权限不足!");
        //判断购买订单商家id 与当前登录商家id 是否一致
        if(!Objects.equals(userInfo.getMerchantId(),merchantInfo.getId())){
            throw new ServiceException("权限不足!");
        }
        if (!Objects.equals(orderInfo.getStatus() , 106L) && !Objects.equals(orderInfo.getStatus(),104L)) {
            throw new ServiceException("签收失败，订单当前处于【"+GroupOrderStatusEnums.getMsg(Math.toIntExact(orderInfo.getStatus()))+"】状态!");
        }
        //判断生态购code 是否存在
        PyErpRandomCode pyErpRandomCode = pyErpRandomCodeService.checkPyErpRandomCodeAndMerchant(new ActSaleCode(req.getCode()).setMerchantId(userInfo.getMerchantId()), PyRandomCodeEnums.OUT_STOCK);
        if (!Objects.equals(pyErpRandomCode.getOrderId() , req.getOrderId())) {
            throw new ServiceException("订单号与code不匹配!");
        }
        //处理签收信息 先更新code 的入库状态
        int noInNum = pyErpRandomCodeService.merInAndSearchNoInNum(pyErpRandomCode);
        //查询订单下的code数量
        if(noInNum == 0){
            //更新订单状态为 301 订单完成
            int update = orderInfoService.updateCardGroupOrderInfo(new CardGroupOrderInfo().setStatus(301L).setId(req.getOrderId()));
            if(update <= 0){
                throw new ServiceException("订单签收异常!");
            }
            //订单完全签收之后赠送生态购积分
            if (Constants.ORDER_TYPE_SHOP.equals(orderInfo.getOrderType()) && orderInfo.getGiveOrderId() == null) {
                asyncAppService.addPointByMallOrder(orderInfo);
                // 商城订单完结
                Map<String, Object> param = ImmutableMap.of("type", Constants.TYPE_SHOP_POINT, "orderId", orderInfo.getId());
                MqUtils.sendMq(MqConstans.QUEUE_ORDER_OVER, JSONTools.obj2json(param));
            }
        }
        return OutDTO.ok()
                     .put("noInNum",noInNum)
                ;

    }


    /**
     * 商家签收生态购订单
     *
     */
    @ResponseBody
    @ApiVersion(1.2)
    @PostMapping(value = "/v1/merchant/sign/order")
    @ApiOperation("商家签收生态购订单")
    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
    @Transactional(rollbackFor = {ServiceException.class,Exception.class}, isolation = Isolation.READ_COMMITTED)
    public OutDTO merchantSignOrderV1(@Validated(Insert.class) @RequestBody RandomCodeMerInReq req) {
        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
        AppAssert.notNull(userInfo, "权限不足!");
        //根据userId 查询商家
        MerchantInfo merchantInfo = merchantApiService.getMerchantByAppUserId(Math.toIntExact(userInfo.getId()));
        AppAssert.notNull(merchantInfo, "权限不足!");
        //判断生态购code 是否存在
        PyErpRandomCode pyErpRandomCode = pyErpRandomCodeService.checkPyErpRandomCodeAndMerchant(new ActSaleCode(req.getCode()).setMerchantId(userInfo.getMerchantId()), PyRandomCodeEnums.OUT_STOCK);
        //查询订单信息
        CardGroupOrderInfo orderInfo = orderInfoService.selectCardGroupOrderInfoById(pyErpRandomCode.getOrderId());
        AppAssert.notNull(orderInfo, "订单不存在!");
        if (!Objects.equals(orderInfo.getStatus() , 106L) && !Objects.equals(orderInfo.getStatus(),104L)) {
            throw new ServiceException("签收失败，订单当前处于【"+GroupOrderStatusEnums.getMsg(Math.toIntExact(orderInfo.getStatus()))+"】状态!");
        }
        //处理签收信息 先更新code 的入库状态
        int noInNum = pyErpRandomCodeService.merInAndSearchNoInNum(pyErpRandomCode);
        //查询订单下的code数量
        if(noInNum == 0){
            //更新订单状态为 301 订单完成
            int update = orderInfoService.updateCardGroupOrderInfo(new CardGroupOrderInfo().setStatus(301L).setId(pyErpRandomCode.getOrderId()));
            if(update <= 0){
                throw new ServiceException("订单签收异常!");
            }
            //订单完全签收之后赠送生态购积分
            if (Constants.ORDER_TYPE_SHOP.equals(orderInfo.getOrderType()) && orderInfo.getGiveOrderId() == null) {
                asyncAppService.addPointByMallOrder(orderInfo);
                // 商城订单完结
                Map<String, Object> param = ImmutableMap.of("type", Constants.TYPE_SHOP_POINT, "orderId", orderInfo.getId());
                MqUtils.sendMq(MqConstans.QUEUE_ORDER_OVER, JSONTools.obj2json(param));
            }
        }
        return OutDTO.ok()
                     .put("noInNum",noInNum)
                ;

    }

}
