Administrator
2025-04-23 595b7935a30e84fba1bc3561d05f9d19d3e32e1f
src/main/java/com/taoke/autopay/service/impl/KeyOrderServiceImpl.java
@@ -1,26 +1,37 @@
package com.taoke.autopay.service.impl;
import com.google.gson.Gson;
import com.taoke.autopay.dao.KeyOrderMapper;
import com.taoke.autopay.dao.WxUserSettingsMapper;
import com.taoke.autopay.dto.ChannelOrderStatistic;
import com.taoke.autopay.dto.DYOrderDto;
import com.taoke.autopay.entity.*;
import com.taoke.autopay.entity.agent.ChannelAgent;
import com.taoke.autopay.entity.agent.ChannelAgentSettings;
import com.taoke.autopay.exception.KeyOrderException;
import com.taoke.autopay.exception.KeyVerifyException;
import com.taoke.autopay.exception.UserCreditException;
import com.taoke.autopay.exception.WxOrderCountException;
import com.taoke.autopay.factory.OrderFactory;
import com.taoke.autopay.service.KeyOrderService;
import com.taoke.autopay.service.SystemConfigService;
import com.taoke.autopay.service.WxUserOrderCountService;
import com.taoke.autopay.service.WxUserSettingService;
import com.taoke.autopay.manager.UserCreditManager;
import com.taoke.autopay.service.*;
import com.taoke.autopay.service.agent.ChannelAgentService;
import com.taoke.autopay.service.agent.ChannelAgentSettingService;
import com.taoke.autopay.service.agent.ChannelAgentSharingRatioService;
import com.taoke.autopay.utils.*;
import com.taoke.autopay.utils.order.DYOrderApi;
import com.taoke.autopay.utils.order.OrderChannelUtil;
import com.taoke.autopay.vo.SubmitKeyInfo;
import com.taoke.autopay.vo.admin.IgnoreAgentOrderSettingVO;
import net.sf.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.net.URI;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -34,6 +45,8 @@
@Service
public class KeyOrderServiceImpl implements KeyOrderService {
    private Logger loggerDebug= LoggerFactory.getLogger("debugLogger");
    @Resource
    private KeyOrderMapper keyOrderMapper;
@@ -46,6 +59,27 @@
    @Resource
    private SystemConfigService systemConfigService;
    @Resource
    private ChannelAgentService channelAgentService;
    @Resource
    private ChannelAgentSharingRatioService channelAgentSharingRatioService;
    @Resource
    private ChannelAgentSettingService channelAgentSettingService;
    @Resource
    private ClientInfoService clientInfoService;
    @Resource
    private PayMoneySettingService payMoneySettingService;
    @Resource
    private WxUserService wxUserService;
    @Resource
    private UserCreditManager userCreditManager;
    @Override
    public KeyOrder selectById(String id) {
@@ -54,11 +88,19 @@
    @Transactional(rollbackFor = Exception.class)
    @Override
    public KeyOrder addKeyOrder(SubmitKeyInfo keyInfo, Long uid, String day) throws KeyOrderException, WxOrderCountException {
    public KeyOrder selectByIdForUpdate(String id) {
        return keyOrderMapper.selectByPrimaryKeyForUpdate(id);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public KeyOrder addKeyOrder(SubmitKeyInfo keyInfo, Long uid, String day, Integer orderType, DYOrderDto orderDto) throws KeyOrderException, WxOrderCountException {
        // 判断提交次数是否过量
        if (uid != null) {
            WxUserSettings settings = wxUserSettingService.getUserSettings(uid);
            wxUserOrderCountService.addOrderCount(uid, OrderCountTypeEnum.SUBMIT_TOKEN_COUNT, day, 1, settings.getTotalOrderCountPerDay());
            OrderCountTypeEnum countType = OrderCountTypeEnum.SUBMIT_TOKEN_COUNT;
            wxUserOrderCountService.addOrderCount(uid, countType, null, day, 1, settings.getTotalOrderCountPerDay());
            wxUserService.setLatestInfoInfo(uid, keyInfo.getIp(), keyInfo.getIpInfo());
        }
        String id = OrderFactory.createId(keyInfo.getKey());
        KeyOrder order = keyOrderMapper.selectById(id);
@@ -66,18 +108,73 @@
            throw new KeyOrderException("请勿重复提交口令");
        }
        order = new KeyOrder();
        // 解析referer中的链接
        if (!StringUtil.isNullOrEmpty(keyInfo.getReferer())) {
            Map<String, String> paramsMap = HttpUtil.getPramsFromUrl(keyInfo.getReferer());
            if (paramsMap.containsKey("a")) {
                String alias = paramsMap.get("a");
                ChannelAgent agent = channelAgentService.selectByAlias(alias);
                if (agent == null) {
                    throw new KeyOrderException("渠道不存在");
                }
                if (agent.getStatus() != ChannelAgent.STATUS_NOMAL) {
                    throw new KeyOrderException("渠道受限");
                }
                // 验证渠道时间
                ChannelAgentSettings settings = channelAgentSettingService.selectByAgentId(agent.getId());
                if (settings != null && !StringUtil.isNullOrEmpty(settings.getStartSubmitTime()) && !StringUtil.isNullOrEmpty(settings.getEndSubmitTime())) {
                    String now = TimeUtil.getGernalTime(System.currentTimeMillis(), "HHmmss");
                    String startTime = settings.getStartSubmitTime().replace(":", "");
                    String endTime = settings.getEndSubmitTime().replace(":", "");
                    if (Integer.parseInt(now) < Integer.parseInt(startTime) || Integer.parseInt(now) > Integer.parseInt(endTime)) {
                        throw new KeyOrderException(String.format("口令提交时间段为:%s-%s", settings.getStartSubmitTime(), settings.getEndSubmitTime()));
                    }
                }
                // 获取渠道忽略订单的配置
                String config = systemConfigService.getValueCache(SystemConfigKeyEnum.IGNORE_AGENT_ORDER_SETTING);
                if (!StringUtil.isNullOrEmpty(config)) {
                    IgnoreAgentOrderSettingVO ignore = JsonUtil.getSimpleGson().fromJson(config, IgnoreAgentOrderSettingVO.class);
                    if (ignore.getPercent() > 0) {
                        // 获取当前代理今日的订单数量
                        KeyOrderMapper.DaoQuery daoQuery = new KeyOrderMapper.DaoQuery();
                        daoQuery.agentId = agent.getId();
                        daoQuery.minCreateTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(System.currentTimeMillis(), "yyyyMMdd"), "yyyyMMdd"));
                        long keyCount = count(daoQuery);
                        if (keyCount > ignore.getBeginCount()) {
                            if ((keyCount - ignore.getBeginCount()) % (100 / ignore.getPercent()) == 0) {
                                order.setIgnore(true);
                            }
                        }
                    }
                }
                order.setAgentId(agent.getId());
            }
        }
        order.setId(id);
        order.setKey(keyInfo.getKey());
        if(!StringUtil.isNullOrEmpty(keyInfo.getMoney())){
        if (!StringUtil.isNullOrEmpty(keyInfo.getMoney())) {
            order.setOrderMoney(new BigDecimal(keyInfo.getMoney()));
        }
        order.setUid(uid);
        order.setState(KeyOrder.STATE_NOT_PROCESS);
        order.setStateDesc("尚未处理");
        order.setCreateTime(new Date());
        if (orderType != Constant.ORDER_TYPE_UNKNOWN) {
            order.setOrderType(orderType);
        }
        if (orderDto != null) {
            order.setOrderNo(orderDto.getOrder_id());
        }
        order.setIp(keyInfo.getIp());
        if (keyInfo.getIpInfo() != null) {
            order.setIpInfo(new Gson().toJson(keyInfo.getIpInfo()));
        }
        keyOrderMapper.insertSelective(order);
        return order;
    }
@@ -99,25 +196,49 @@
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void paySuccess(String id, String stateDesc,String day) throws WxOrderCountException {
    public void paySuccess(String id, String stateDesc, String day, String payMerchant) throws WxOrderCountException {
        KeyOrder old = keyOrderMapper.selectByPrimaryKeyForUpdate(id);
        if(old==null){
           return;
        }
        if(old.getState() == KeyOrder.STATE_PAY){
        if (old == null) {
            return;
        }
        if(old.getUid()!=null) {
            wxUserOrderCountService.addOrderCount(old.getUid(),OrderCountTypeEnum.DY_ORDER_PAY,day,1,null);
        if (old.getState() == KeyOrder.STATE_PAY) {
            return;
        }
        if (old.getUid() != null) {
            Integer orderType = old.getOrderType();
            wxUserOrderCountService.addOrderCount(old.getUid(), (orderType == null || orderType == Constant.ORDER_TYPE_DY) ? OrderCountTypeEnum.DY_ORDER_PAY : OrderCountTypeEnum.KS_ORDER_PAY, OrderChannelUtil.getChannelByKey(old.getOrderChannel()), day, 1, null);
        }
        KeyOrder orderUpdate = new KeyOrder();
        orderUpdate.setId(id);
        orderUpdate.setState(KeyOrder.STATE_PAY);
        orderUpdate.setStateDesc(stateDesc);
        if(old.getPayTime()==null){
        orderUpdate.setPayMerchant(payMerchant);
        if (old.getPayTime() == null) {
            orderUpdate.setPayTime(new Date());
        }
        update(orderUpdate);
        // 增加积分
        try {
            boolean creditEnable = true;
            // 判断代理是否允许增加积分
            Long agengId = old.getAgentId();
            if(agengId!=null) {
                ChannelAgentSettings agentSettings =   channelAgentSettingService.selectByAgentId(agengId);
                if(agentSettings!=null&&agentSettings.getCreditEnable()!=null) {
                    creditEnable =agentSettings.getCreditEnable();
                }
            }
            if(creditEnable) {
                if (old.getOrderType() == Constant.ORDER_TYPE_DY) {
                    userCreditManager.addDYOrderPayRecord(old.getUid(), id);
                } else if (old.getOrderType() == Constant.ORDER_TYPE_KS) {
                    userCreditManager.addKSOrderPayRecord(old.getUid(), id);
                }
            }
        } catch (UserCreditException e) {
            loggerDebug.error("增加积分出错:"+id, e);
        }
    }
    @Transactional(rollbackFor = Exception.class)
@@ -150,45 +271,127 @@
    }
    @Override
    public Long getCanDistributeUid() {
    public List<KeyOrder> listWithUser(KeyOrderMapper.DaoQuery query) {
        return keyOrderMapper.listWithUser(query);
    }
    @Override
    public long countWithUser(KeyOrderMapper.DaoQuery query) {
        return keyOrderMapper.countWithUser(query);
    }
    @Override
    public ChannelOrderStatistic statisticWithUser(KeyOrderMapper.DaoQuery query) {
        Map<OrderChannelEnum, BigDecimal> shareMoneyMap = channelAgentSharingRatioService.getShareMoneyMap(query.agentId);
        List<ChannelOrderStatistic> channelOrderStatisticList = keyOrderMapper.statisticChannelOrders(query);
        BigDecimal totalMoney = new BigDecimal(0);
        long totalOrderCount = 0;
        for (ChannelOrderStatistic s : channelOrderStatisticList) {
            for (OrderChannelEnum channel : OrderChannelEnum.values()) {
                if (channel.getKey().equalsIgnoreCase(s.getOrderChannel())) {
                    if (shareMoneyMap.containsKey(channel)) {
                        totalMoney = totalMoney.add(shareMoneyMap.get(channel).multiply(new BigDecimal(s.getCount())));
                    }
                    break;
                }
            }
            totalOrderCount += s.getCount();
        }
        long userCount = keyOrderMapper.countUser(query);
        ChannelOrderStatistic statistic = new ChannelOrderStatistic();
        statistic.setUserCount(userCount);
        statistic.setMoney(totalMoney);
        statistic.setCount(totalOrderCount);
        return statistic;
    }
    @Override
    public List<ChannelOrderStatistic> statisticChannelOrders(Long agentId, Date startTime, Date endTime) {
        KeyOrderMapper.DaoQuery daoQuery = new KeyOrderMapper.DaoQuery();
        daoQuery.minCreateTime = startTime;
        daoQuery.maxCreateTime = endTime;
        daoQuery.agentId = agentId;
        daoQuery.state = KeyOrder.STATE_PAY;
        daoQuery.hasPayTime = true;
        // 将数据拉出来
        long count = keyOrderMapper.count(daoQuery);
        daoQuery.count = (int) count;
        List<KeyOrder> orderList = keyOrderMapper.list(daoQuery);
        Map<String, Set<Long>> uidsMap = new HashMap<>();
        Map<String, Integer> countMap = new HashMap<>();
        Map<String, BigDecimal> moneyMap = new HashMap<>();
        Set<String> orderIds = new HashSet<>();
        for (KeyOrder order : orderList) {
            String orderId = order.getOrderType() + "#" + order.getOrderNo();
            if (!StringUtil.isNullOrEmpty(order.getOrderNo())) {
                if (orderIds.contains(orderId)) {
                    continue;
                }
                orderIds.add(orderId);
            }
            String orderChannel = order.getOrderChannel();
            if (!uidsMap.containsKey(orderChannel)) {
                uidsMap.put(orderChannel, new HashSet<>());
            }
            uidsMap.get(orderChannel).add(order.getUid());
            if (!countMap.containsKey(orderChannel)) {
                countMap.put(orderChannel, 0);
            }
            countMap.put(orderChannel, countMap.get(orderChannel) + 1);
            if (!moneyMap.containsKey(orderChannel)) {
                moneyMap.put(orderChannel, new BigDecimal(0));
            }
            moneyMap.put(orderChannel, moneyMap.get(orderChannel).add(order.getOrderMoney()));
        }
        List<ChannelOrderStatistic> results = new ArrayList<>();
        for (String orderChannel : moneyMap.keySet()) {
            ChannelOrderStatistic statistic = new ChannelOrderStatistic();
            statistic.setCount(countMap.get(orderChannel));
            statistic.setMoney(moneyMap.get(orderChannel));
            statistic.setUserCount(uidsMap.get(orderChannel).size());
            statistic.setOrderChannel(orderChannel);
            results.add(statistic);
        }
        return results;
    }
    @Override
    public Long getCanDistributeUid(int maxQueueSize) {
        // 最近1小时有活跃,且不算12以上未执行的数据
        List<OrderDistributeCountInfo> list = keyOrderMapper.listDistributeUids(new Date(System.currentTimeMillis() - 1000 * 60 * 60L),new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 12L));
        List<OrderDistributeCountInfo> list = keyOrderMapper.listDistributeUids(new Date(System.currentTimeMillis() - 1000 * 60 * 31L), new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 12L));
        if (list == null || list.size() == 0) {
            return null;
        }
        // 排除重新分配的设备
        List<Long> excludeIds = clientInfoService.getRePayClientIds();
        for (int i = 0; i < list.size(); i++) {
            if (excludeIds.contains(list.get(i).getUid())) {
                list.remove(i);
                i--;
            }
        }
        List<OrderDistributeCountInfo> filterList = new ArrayList<>();
        // count小于2直接视为0
        for (OrderDistributeCountInfo info : list) {
            if (info.getCount() < 2) {
                info.setCount(0);
            if (info.getCount() >= maxQueueSize) {
                continue;
            }
            filterList.add(info);
        }
        if (filterList.size() <= 0) {
            return null;
        }
        Comparator<OrderDistributeCountInfo> cm = new Comparator<OrderDistributeCountInfo>() {
            @Override
            public int compare(OrderDistributeCountInfo o1, OrderDistributeCountInfo o2) {
                return o1.getCount() - o2.getCount();
            }
        };
        list.sort(cm);
        if (list.get(0).getCount() == 0) {
            // 处理大多数设备都没有分配的情况
            // 将为0的数据随机分配
            List<OrderDistributeCountInfo> tempList = new ArrayList<>();
            for (OrderDistributeCountInfo info : list) {
                if (info.getCount() == 0) {
                    tempList.add(info);
                }
            }
            int index = new Random().nextInt(tempList.size());
            if (index < 0) {
                index = 0;
            }
            if (index >= tempList.size()) {
                index = tempList.size() - 1;
            }
            return tempList.get(index).getUid();
        }
        return list.get(0).getUid();
        return ClientDistributeUtil.computeDistributeClient(filterList);
    }
    @Override
@@ -202,15 +405,26 @@
    }
    @Override
    public DYOrderDto verifyKey(String orderNoDesc, String orderStatus, String money) throws  KeyVerifyException {
        int orderType= Constant.ORDER_TYPE_UNKNOWN;
        if(orderNoDesc.contains("抖音")){
            orderType = Constant.ORDER_TYPE_DY;
        }else  if(orderNoDesc.contains("快手")){
            orderType = Constant.ORDER_TYPE_KS;
    public DYOrderDto verifyKey(String orderNoDesc, String orderStatus, String money, Long uid, String keyId) throws KeyVerifyException {
        int orderType = AlipayOrderUtil.getOrderType(orderNoDesc);
        if (uid != null) {
            WxUserSettings settings = wxUserSettingService.getUserSettings(uid);
            OrderCountTypeEnum orderCountType = OrderCountTypeEnum.SUBMIT_TOKEN_COUNT;
            int maxCount = settings.getTotalOrderCountPerDay();
            switch (orderType) {
                case Constant.ORDER_TYPE_DY:
                    orderCountType = OrderCountTypeEnum.DY_ORDER_PAY;
                    maxCount = settings.getDyOrderCountPerDay();
                    break;
                case Constant.ORDER_TYPE_KS:
                    orderCountType = OrderCountTypeEnum.KS_ORDER_PAY;
                    maxCount = settings.getKsOrderCountPerDay();
                    break;
            }
        }
        String orderNo= "";
        String orderNo = "";
        // 匹配连续的数字
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(orderNoDesc);
@@ -223,50 +437,78 @@
            }
        }
            if(orderType==Constant.ORDER_TYPE_UNKNOWN){
                throw new KeyVerifyException(KeyVerifyException.CODE_ORDER_TYPE_ERROR, "未定义的订单类型");
            }
        if (orderType == Constant.ORDER_TYPE_UNKNOWN) {
            throw new KeyVerifyException(KeyVerifyException.CODE_ORDER_TYPE_ERROR, "未定义的订单类型");
        }
            if (!StringUtil.isNullOrEmpty(orderStatus)&&!orderStatus.contains("未支付")) {
                throw new KeyVerifyException(KeyVerifyException.CODE_ORDER_STATUS_ERROR, "订单状态:"+orderStatus);
            }
            DYOrderDto dyOrderDto=null;
            // 先匹配订单
            try {
                if(orderType == Constant.ORDER_TYPE_DY&&!StringUtil.isNullOrEmpty(orderNo)){
                    dyOrderDto = DYOrderApi.getOrderDetail(orderNo);
                    if(dyOrderDto!=null){
                        // 验证金额
                        if( dyOrderDto.getPay_amount().intValue()!= new BigDecimal(money).multiply(new BigDecimal(100)).setScale(0).intValue()){
                            throw new KeyVerifyException(KeyVerifyException.CODE_ORDER_MONEY_NOT_MATCH ,String.format("支付金额与订单金额不一致:%s-%d",money,dyOrderDto.getPay_amount() ));
                        }
        if (!StringUtil.isNullOrEmpty(orderStatus) && !orderStatus.contains("未支付")) {
            throw new KeyVerifyException(KeyVerifyException.CODE_ORDER_STATUS_ERROR, "订单状态:" + orderStatus);
        }
        DYOrderDto dyOrderDto = null;
        // 先匹配订单
        try {
            if (orderType == Constant.ORDER_TYPE_DY && !StringUtil.isNullOrEmpty(orderNo)) {
                dyOrderDto = DYOrderApi.getOrderDetail(orderNo);
                if (dyOrderDto != null && false) {
                    // 验证金额
                    if (dyOrderDto.getPay_amount().intValue() != new BigDecimal(money).multiply(new BigDecimal(100)).setScale(0).intValue()) {
                        throw new KeyVerifyException(KeyVerifyException.CODE_ORDER_MONEY_NOT_MATCH, String.format("支付金额与订单金额不一致:%s-%d", money, dyOrderDto.getPay_amount()));
                    }
                }else{
                    throw new KeyOrderException("抖音订单获取失败");
                    // 验证订单号是否已经存在
                    KeyOrderMapper.DaoQuery query = new KeyOrderMapper.DaoQuery();
                    query.orderNo = orderNo;
                    query.orderType = orderType;
                    if (count(query) > 1) {
                        throw new KeyVerifyException(KeyVerifyException.CODE_ORDER_NO_REPEAT, "订单号重复提交");
                    }
                }
            }catch(KeyOrderException e){
                // 抖音订单未验证通过,匹配金额
                // 验证提交的金额是否正确
                String moneyStr =  systemConfigService.getValueCache(SystemConfigKeyEnum.PAY_MONEY_LIST);
                if(StringUtil.isNullOrEmpty(moneyStr)){
                    throw new KeyVerifyException(KeyVerifyException.CODE_KEY_MONEY_NOT_MATCH ,"尚未配置金额");
                }
                JSONArray array=JSONArray.fromObject(moneyStr);
                Set<String> moneySet=new HashSet<>();
                for(int i=0;i<array.size();i++){
                    moneySet.add(MoneyUtil.getMoneyStr(new BigDecimal(array.optString(i))));
                }
                // 匹配金额
                if(!moneySet.contains(money)){
                    throw new KeyVerifyException(KeyVerifyException.CODE_KEY_MONEY_NOT_MATCH, String.format("金额未在系统设置中:%s",money));
                }
            } else {
                throw new KeyOrderException("抖音订单获取失败");
            }
        } catch (KeyOrderException e) {
            // 抖音订单未验证通过,匹配金额
            // 验证提交的金额是否正确
            Set<String> moneySet = payMoneySettingService.listAllMoneyAsStr();
            // 匹配金额
            if (!moneySet.contains(money)) {
                throw new KeyVerifyException(KeyVerifyException.CODE_KEY_MONEY_NOT_MATCH, String.format("金额未在系统设置中:%s", money));
            }
        }
            return dyOrderDto;
        return dyOrderDto;
    }
    @Override
    public void removeDistributedClient(String id) {
        keyOrderMapper.removeDistributedClient(id);
    }
    @Override
    public List<Long> listAgentId(KeyOrderMapper.DaoQuery query) {
        return keyOrderMapper.listAgentId(query);
    }
    @Override
    public long countAgentId(KeyOrderMapper.DaoQuery query) {
        return keyOrderMapper.countAgentId(query);
    }
    @Override
    public long countUserNotDoOrder(Long uid, Date minCreateTime) {
        KeyOrderMapper.DaoQuery daoQuery = new KeyOrderMapper.DaoQuery();
        daoQuery.uid = uid;
        daoQuery.stateList = Arrays.asList(new Integer[]{KeyOrder.STATE_NOT_PROCESS, KeyOrder.STATE_NOT_PAY});
        daoQuery.minCreateTime = minCreateTime;
        return keyOrderMapper.count(daoQuery);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void rejectPay(String id, String rejectMsg) {
        KeyOrder keyOrder = new KeyOrder();
        keyOrder.setId(id);
        keyOrder.setState(KeyOrder.STATE_REJECT_PAY);
        keyOrder.setStateDesc(rejectMsg);
        update(keyOrder);
    }
}