admin
2024-07-25 bd014bc7bfbc43a071f682f25b473a1cf103027e
代理新功能完善
17个文件已添加
24个文件已修改
2279 ■■■■ 已修改文件
pom.xml 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/controller/WebApiController.java 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/controller/admin/AdminOrderController.java 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/controller/admin/AdminSettingsController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/controller/client/OrderController.java 114 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/dao/KeyOrderMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/dao/agent/ChannelAgentMapper.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/dto/DYOrderDto.java 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/dto/DYSkuOrderDto.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/dto/DYSubsidyDto.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/dto/admin/OrderExcelDataDto.java 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/entity/KeyOrder.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/entity/OrderChannelEnum.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/entity/SystemConfigKeyEnum.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/entity/agent/ChannelAgent.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/entity/agent/ChannelAgentOrderRecord.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/entity/agent/ChannelAgentSettings.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/entity/agent/ChannelAgentSharingRatio.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/entity/agent/ChannelAgentWidthDrawRecord.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/exception/KeyVerifyException.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/service/KeyOrderService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/service/impl/KeyOrderServiceImpl.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/utils/AgentAliasUtil.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/utils/AlipayOrderUtil.java 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/utils/Constant.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/utils/HttpUtil.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/utils/order/DYOrderApi.java 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/vo/SubmitKeyInfo.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/taoke/autopay/vo/admin/OrderSearchVO.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ChannelAgentMapper.xml 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/KeyOrderMapper.xml 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/admin/order-list.html 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/admin/pay_settings.html 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/admin/settings_edit.html 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/index2.html 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/taoke/autopay/AutopayApplicationTests.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/taoke/autopay/KeyTest.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/taoke/autopay/LogTest.java 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/taoke/autopay/MapperTest.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/taoke/autopay/WxUserTests.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -87,6 +87,13 @@
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
            <exclusions>
                <exclusion>
                        <groupId>commons-io</groupId>
                        <artifactId>commons-io</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
@@ -144,11 +151,11 @@
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
        <!--<dependency>-->
            <!--<groupId>commons-io</groupId>-->
            <!--<artifactId>commons-io</artifactId>-->
            <!--<version>2.5</version>-->
        <!--</dependency>-->
        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
        <dependency>
@@ -229,6 +236,34 @@
        <!--</dependency>-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>4.0.1</version>
            <!--<exclusions>-->
                <!--<exclusion>-->
                    <!--<groupId>commons-io</groupId>-->
                    <!--<artifactId>commons-io</artifactId>-->
                <!--</exclusion>-->
            <!--</exclusions>-->
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.9.2</version>
        </dependency>
    </dependencies>
    <build>
src/main/java/com/taoke/autopay/controller/WebApiController.java
@@ -1,19 +1,18 @@
package com.taoke.autopay.controller;
import com.taoke.autopay.dto.DYOrderDto;
import com.taoke.autopay.dto.WXAppInfoDto;
import com.taoke.autopay.entity.KeyOrder;
import com.taoke.autopay.entity.SystemConfigKeyEnum;
import com.taoke.autopay.entity.WxUserInfo;
import com.taoke.autopay.exception.KeyOrderException;
import com.taoke.autopay.exception.KeyVerifyException;
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.WxUserService;
import com.taoke.autopay.utils.*;
import com.taoke.autopay.vo.SubmitKeyInfo;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -23,15 +22,11 @@
import org.yeshi.utils.UrlUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
@Controller
@RequestMapping("webapi")
@@ -82,7 +77,47 @@
        }
    }
    private void addKey(SubmitKeyInfo keyInfo, Long wxUid) throws KeyOrderException, WxOrderCountException {
    private void addKey(SubmitKeyInfo keyInfo, Long wxUid) throws KeyVerifyException, KeyOrderException, WxOrderCountException {
       // 解析链接
        List<String> urllist = UrlUtils.parseUrlsFromText(keyInfo.getKey());
        String verifyAlipayKey = systemConfigService.getValueCache(SystemConfigKeyEnum.ALIPAY_KEY_VERIFY);
        if(verifyAlipayKey!=null&&verifyAlipayKey.trim().equalsIgnoreCase("1")) {
            try {
                // 需要验证支付宝口令
                if (urllist.size() < 1) {
                    throw new Exception("口令中不包含链接");
                }
                AlipayOrderUtil.AlipayOrderTradeInfo tradeInfo = AlipayOrderUtil.getTradeInfo(urllist.get(0));
                String orderStatus = "";
                switch (tradeInfo.getStatus()) {
                    case AlipayOrderUtil.AlipayOrderTradeInfo.STATUS_CANCELED:
                        orderStatus = "订单已取消";
                        break;
                    case AlipayOrderUtil.AlipayOrderTradeInfo.STATUS_PAY:
                        orderStatus = "订单已支付";
                        break;
                    case AlipayOrderUtil.AlipayOrderTradeInfo.STATUS_NOT_PAY:
                        orderStatus = "订单未支付";
                        break;
                }
                if (tradeInfo == null) {
                    throw new Exception("口令内容获取失败");
                }
                // 验证内容
                DYOrderDto dto = keyOrderService.verifyKey(tradeInfo.getGoodsTitle(), orderStatus, tradeInfo.getItemRealAmount());
            }catch(KeyVerifyException ee){
                throw  ee;
            }
            catch(Exception e){
                throw new KeyVerifyException(KeyVerifyException.CODE_COMMON, e.getMessage());
            }
        }
        KeyOrder order = keyOrderService.addKeyOrder(keyInfo, wxUid, TimeUtil.getGernalTime(System.currentTimeMillis(), "yyyyMMdd"));
        Long uid = keyOrderService.getCanDistributeUid();
        if (uid != null) {
@@ -96,15 +131,26 @@
    }
    private void verifySubmitKey(String key) throws Exception{
        List<String> urllist = UrlUtils.parseUrlsFromText(key);
        if (urllist.isEmpty() || !urllist.get(0).contains("ur.alipay.com")) {
           throw new Exception("不包含支付宝链接");
        }
        if(!key.contains("支付宝")){
            throw new Exception("没包含支付宝汉字");
        }
    }
    @ResponseBody
    @RequestMapping(value = "submitKeyV2")
    public String submitKeyV2(SubmitKeyInfo keyInfo, HttpSession session) {
        WxUserInfo user = (WxUserInfo) session.getAttribute(Constant.SESSION_KEY_USER);
        if (StringUtil.isNullOrEmpty(keyInfo.getKey())) {
            return JsonUtil.loadFalseResult(0, "请上传key");
            return JsonUtil.loadFalseResult("请上传key");
        }
        List<String> urllist = UrlUtils.parseUrlsFromText(keyInfo.getKey());
        if (urllist.isEmpty() || !urllist.get(0).contains("ur.alipay.com")) {
        try{
            verifySubmitKey(keyInfo.getKey());
        }catch (Exception e){
            return JsonUtil.loadFalseResult("支付宝口令不正确");
        }
@@ -131,6 +177,15 @@
            e.printStackTrace();
            return JsonUtil.loadFalseResult(e.getMessage());
        } catch (WxOrderCountException e) {
            return JsonUtil.loadFalseResult(e.getMessage());
        } catch (KeyVerifyException e) {
            switch (e.getCode()){
                case KeyVerifyException.CODE_KEY_MONEY_NOT_MATCH:
                    return JsonUtil.loadFalseResult("该笔订单有误,不予提交");
                case KeyVerifyException.CODE_ORDER_MONEY_NOT_MATCH:
                    return JsonUtil.loadFalseResult("提交金额不匹配");
            }
            logger.debug("口令验证结果异常:{}-{}", keyInfo.getKey(), e.getMessage());
            return JsonUtil.loadFalseResult(e.getMessage());
        }
    }
@@ -145,16 +200,19 @@
     **/
    @ResponseBody
    @RequestMapping(value = "submitKeyV3")
    public String submitKeyV3(SubmitKeyInfo keyInfo, HttpSession session) {
    public String submitKeyV3(SubmitKeyInfo keyInfo, HttpSession session, HttpServletRequest request) {
       String referer = request.getHeader("Referer");
        keyInfo.setReferer(referer);
        WxUserInfo user = (WxUserInfo) session.getAttribute(Constant.SESSION_KEY_USER);
        if (StringUtil.isNullOrEmpty(keyInfo.getKey())) {
            return JsonUtil.loadFalseResult(0, "请上传key");
            return JsonUtil.loadFalseResult( "请上传key");
        }
        if (StringUtil.isNullOrEmpty(keyInfo.getMoney())) {
            return JsonUtil.loadFalseResult(0, "请上传money");
        }
        List<String> urllist = UrlUtils.parseUrlsFromText(keyInfo.getKey());
        if (urllist.isEmpty() || !urllist.get(0).contains("ur.alipay.com")) {
//        if (StringUtil.isNullOrEmpty(keyInfo.getMoney())) {
//            return JsonUtil.loadFalseResult("请上传money");
//        }
        try{
            verifySubmitKey(keyInfo.getKey());
        }catch (Exception e){
            return JsonUtil.loadFalseResult("支付宝口令不正确");
        }
        // 验证提交时间
@@ -167,19 +225,6 @@
        String now = TimeUtil.getGernalTime(System.currentTimeMillis(),"HHmmss");
        if(Integer.parseInt(now)<Integer.parseInt(startTime)||Integer.parseInt(now)>Integer.parseInt(endTime)){
            return JsonUtil.loadFalseResult(String.format("口令提交时间段为:%s-%s",timeStr.split(",")[0],timeStr.split(",")[1]));
        }
        // 验证提交的金额是否正确
       String moneyStr =  systemConfigService.getValueCache(SystemConfigKeyEnum.PAY_MONEY_LIST);
       if(StringUtil.isNullOrEmpty(moneyStr)){
           return JsonUtil.loadFalseResult("尚未配置金额");
       }
       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(MoneyUtil.getMoneyStr(new BigDecimal(keyInfo.getMoney())))){
            return JsonUtil.loadFalseResult("提交金额不符合要求");
        }
        if (user == null) {
            // 先保存KEY
@@ -204,23 +249,41 @@
            return JsonUtil.loadFalseResult(e.getMessage());
        } catch (WxOrderCountException e) {
            return JsonUtil.loadFalseResult(e.getMessage());
        } catch (KeyVerifyException e) {
            logger.debug("口令校验失败:{}-{}-{}", keyInfo.getKey(), e.getCode(), e.getMessage());
            switch (e.getCode()){
                case KeyVerifyException.CODE_KEY_MONEY_NOT_MATCH:
                    return JsonUtil.loadFalseResult("该笔订单有误,不予提交");
                case KeyVerifyException.CODE_ORDER_MONEY_NOT_MATCH:
                    return JsonUtil.loadFalseResult("提交金额不匹配");
            }
            return JsonUtil.loadFalseResult(e.getMessage());
        }
    }
    @RequestMapping(value = "wxLogin")
    public void wxLogin(String code, String state, HttpServletResponse response, HttpSession session) throws IOException {
    public void wxLogin(String code, String state, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
        // 根据code获取openid
        wxLogger.info("微信授权回调:{} code-{}", session.getId(), code);
        SubmitKeyInfo alipayKeyInfo = (SubmitKeyInfo) session.getAttribute(Constant.SESSION_KEY_TEMP_ALIPAY_KEY);
        wxLogger.info("微信授权回调:{} code-{} referer-{}", session.getId(), code, alipayKeyInfo.getReferer());
        String failLink = systemConfigService.getValueCache(SystemConfigKeyEnum.WX_LOGIN_FAIL_LINK);
        String referer = alipayKeyInfo.getReferer();
        try {
            WXAppInfoDto wxApp = systemConfigService.getWxAppInfoCache();
            String successLink = systemConfigService.getValueCache(SystemConfigKeyEnum.WX_LOGIN_SUCCESS_LINK);
            if(!StringUtil.isNullOrEmpty(referer)){
                Map<String, String> params = HttpUtil.getPramsFromUrl(referer);
                params.put("state","SUCCESS");
                successLink = HttpUtil.getWholeUrl(HttpUtil.getUrlWithoutParams(referer),params);
            }
            WxApiUtil.WXAccessTokenInfo tokenInfo = WxApiUtil.getAcessTokenInfo(code, wxApp);
            if (tokenInfo != null && !StringUtil.isNullOrEmpty(tokenInfo.getOpenid())) {
                WxUserInfo user = wxUserService.login(tokenInfo.getOpenid());
                session.setAttribute(Constant.SESSION_KEY_USER, user);
                wxLogger.info("微信保存用户信息:{} id-{}", session.getId(), user.getId());
                SubmitKeyInfo alipayKeyInfo = (SubmitKeyInfo) session.getAttribute(Constant.SESSION_KEY_TEMP_ALIPAY_KEY);
                wxLogger.info("从session读取到key:{}", alipayKeyInfo);
                if (alipayKeyInfo != null) {
                    addKey(alipayKeyInfo, user.getId());
@@ -231,6 +294,11 @@
        } catch (Exception e) {
            e.printStackTrace();
            wxLogger.error("授权失败:{}", e.getMessage());
            if(!StringUtil.isNullOrEmpty(referer)){
                Map<String, String> params = HttpUtil.getPramsFromUrl(referer);
                params.put("state","FAIL");
                failLink = HttpUtil.getWholeUrl(HttpUtil.getUrlWithoutParams(referer),params);
            }
        }
        response.sendRedirect(failLink);
    }
src/main/java/com/taoke/autopay/controller/admin/AdminOrderController.java
@@ -1,17 +1,22 @@
package com.taoke.autopay.controller.admin;
import com.alibaba.excel.EasyExcel;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.sun.org.apache.bcel.internal.generic.BREAKPOINT;
import com.taoke.autopay.dao.KeyOrderMapper;
import com.taoke.autopay.dto.admin.OrderExcelDataDto;
import com.taoke.autopay.entity.*;
import com.taoke.autopay.factory.OrderFactory;
import com.taoke.autopay.service.ClientInfoService;
import com.taoke.autopay.service.KeyOrderService;
import com.taoke.autopay.utils.Constant;
import com.taoke.autopay.utils.TimeUtil;
import com.taoke.autopay.vo.admin.AdminOrderVO;
import com.taoke.autopay.vo.admin.OrderSearchVO;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -21,7 +26,10 @@
import org.yeshi.utils.StringUtil;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
@Controller
@@ -55,20 +63,27 @@
    @ResponseBody
    @RequestMapping("list")
    public String listOrder(String key, int page, int limit) {
    public String listOrder(OrderSearchVO search, int page, int limit) {
        //先查询所有的数据
        KeyOrderMapper.DaoQuery query = new KeyOrderMapper.DaoQuery();
        query.sortList=Arrays.asList(new String[]{"create_time desc"});
        query.start = (page - 1) * limit;
        query.count = limit;
        if (!StringUtil.isNullOrEmpty(key)) {
            if (key.length() > 10 || !NumberUtil.isNumeric(key.trim())) {
        if (!StringUtil.isNullOrEmpty(search.getKey())) {
            if (search.getKey().length() > 10 || !NumberUtil.isNumeric(search.getKey().trim())) {
                // 订单号
                query.orderNo = key.trim();
                query.orderNo = search.getKey().trim();
            } else {
                // 用户ID
                query.uid = Long.parseLong(key.trim());
                query.uid = Long.parseLong(search.getKey().trim());
            }
        }
        if (!StringUtil.isNullOrEmpty(search.getStartDate())) {
            query.minCreateTime =new Date(TimeUtil.convertToTimeTemp(search.getStartDate(),"yyyy-MM-dd"));
        }
        if (!StringUtil.isNullOrEmpty(search.getEndDate())) {
            query.maxCreateTime =TimeUtil.getNextDay(1,new Date(TimeUtil.convertToTimeTemp(search.getEndDate(),"yyyy-MM-dd")).getTime());
        }
        List<KeyOrder> orderList = keyOrderService.list(query);
@@ -98,4 +113,141 @@
        return JsonUtil.loadTrueResult(data);
    }
    @RequestMapping("downLoadOrder")
    public void downLoadOrder(OrderSearchVO search, HttpServletResponse response) throws IOException {
        KeyOrderMapper.DaoQuery query = new KeyOrderMapper.DaoQuery();
        if (!StringUtil.isNullOrEmpty(search.getKey())) {
            if (search.getKey().length() > 10 || !NumberUtil.isNumeric(search.getKey().trim())) {
                // 订单号
                query.orderNo = search.getKey().trim();
            } else {
                // 用户ID
                query.uid = Long.parseLong(search.getKey().trim());
            }
        }
        if (!StringUtil.isNullOrEmpty(search.getStartDate())) {
            query.minCreateTime =new Date(TimeUtil.convertToTimeTemp(search.getStartDate(),"yyyy-MM-dd"));
        }
        if (!StringUtil.isNullOrEmpty(search.getEndDate())) {
            query.maxCreateTime =TimeUtil.getNextDay(1,new Date(TimeUtil.convertToTimeTemp(search.getEndDate(),"yyyy-MM-dd")).getTime());
        }
        query.sortList=Arrays.asList(new String[]{"create_time desc"});
        long count = keyOrderService.count(query);
        query.start=0;
        query.count = (int)count;
        List<KeyOrder> orderList = keyOrderService.list(query);
        // 统计订单与金额
        Map<Long,Integer> userOrderCountMap=new HashMap<>();
        Map<Long, BigDecimal> userOrderMoneyMap=new HashMap<>();
        Map<Long, ClientInfo> payDeviceMap=new HashMap<>();
        List<OrderExcelDataDto> dataList=new ArrayList<>();
        for(KeyOrder order:orderList){
            if(!userOrderCountMap.containsKey(order.getUid())){
                userOrderCountMap.put(order.getUid(),1);
            }else{
                userOrderCountMap.put(order.getUid(),  userOrderCountMap.get(order.getUid())+1);
            }
            if(!userOrderMoneyMap.containsKey(order.getUid())){
                userOrderMoneyMap.put(order.getUid(),new BigDecimal(0));
            }
            if(order.getOrderMoney()!=null) {
                userOrderMoneyMap.put(order.getUid(), userOrderMoneyMap.get(order.getUid()).add(order.getOrderMoney()));
            }
            if(!payDeviceMap.containsKey(order.getDistributeClientUid())&&order.getDistributeClientUid()!=null) {
                ClientInfo clientInfo = clientInfoService.selectByPrimaryKey(order.getDistributeClientUid());
                if(clientInfo!=null) {
                    payDeviceMap.put(clientInfo.getId(), clientInfo);
                }
            }
        }
        for(KeyOrder order:orderList){
            OrderExcelDataDto dto=new OrderExcelDataDto();
            dto.setId(order.getId());
            dto.setCreateTime(TimeUtil.getGernalTime(order.getCreateTime()));
            dto.setOrderMoney(order.getOrderMoney()==null?"":order.getOrderMoney().toString());
            if(order.getOrderChannel()!=null) {
                switch (order.getOrderChannel()) {
                    case Constant
                            .ORDER_CHANNEL_CYX:
                        dto.setOrderChannel("超佣享");
                        break;
                    case Constant
                            .ORDER_CHANNEL_BPS:
                        dto.setOrderChannel("爆品社");
                        break;
                    default:
                        dto.setOrderChannel("");
                }
            }else{
                dto.setOrderChannel("");
            }
            dto.setOrderNo(order.getOrderNo());
            if(order.getOrderType()!=null) {
                switch (order.getOrderType()) {
                    case Constant.ORDER_TYPE_DY:
                        dto.setPlatform("抖音");
                        break;
                    case Constant.ORDER_TYPE_KS:
                        dto.setPlatform("快手");
                        break;
                    default:
                        dto.setPlatform("");
                }
            }else{
                dto.setPlatform("");
            }
            if(order.getPayType()!=null) {
                switch (order.getPayType()) {
                    case Constant.PAY_TYPE_WITH_ORDER_NO:
                        dto.setPayType("按订单");
                        break;
                    case Constant.PAY_TYPE_WITH_MONEY:
                        dto.setPayType("按金额");
                        break;
                    default:
                        dto.setPayType("");
                }
            }else{
                dto.setPayType("");
            }
            dto.setUid(order.getUid());
            if(order.getState()==KeyOrder.STATE_PAY){
                dto.setPaySuccess("是");
            }else {
                dto.setPaySuccess("否");
            }
            dto.setStateDesc(order.getStateDesc());
            dto.setTotalCount(userOrderCountMap.get(order.getUid()));
            dto.setTotalMoney(userOrderMoneyMap.get(order.getUid()).toString());
            dto.setKey(order.getKey());
            if(order.getPayTime()!=null){
                dto.setPayTime(TimeUtil.getGernalTime(order.getPayTime().getTime(),"yyyy-MM-dd HH:mm:ss"));
            }
            ClientInfo device = payDeviceMap.get(order.getDistributeClientUid());
            if(device!=null){
                dto.setPayDevice(device.getAccount());
            }else{
                dto.setPayDevice("");
            }
            dataList.add(dto);
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName= URLEncoder.encode(TimeUtil.getGernalTime(System.currentTimeMillis(),"yyyyMMdd_HHmmss"),"UTF-8");
        response.setHeader("Content-disposition","attachment;filename*=utf-8''"+fileName+".xlsx");
        EasyExcel.write(response.getOutputStream(),OrderExcelDataDto.class).sheet("订单").doWrite(dataList);
    }
}
src/main/java/com/taoke/autopay/controller/admin/AdminSettingsController.java
@@ -38,7 +38,8 @@
        SystemConfigKeyEnum[] keys = new SystemConfigKeyEnum[]{
                SystemConfigKeyEnum.DY_ORDER_MAX_PAY_COUNT_DEFAULT,
                SystemConfigKeyEnum.KS_ORDER_MAX_PAY_COUNT_DEFAULT,
                SystemConfigKeyEnum.ORDER_MAX_SUBMIT_COUNT_DEFAULT
                SystemConfigKeyEnum.ORDER_MAX_SUBMIT_COUNT_DEFAULT,
                SystemConfigKeyEnum.ALIPAY_KEY_VERIFY
        };
        JSONObject data = new JSONObject();
        for (SystemConfigKeyEnum key : keys) {
@@ -56,7 +57,8 @@
        SystemConfigKeyEnum[] keys = new SystemConfigKeyEnum[]{
                SystemConfigKeyEnum.DY_ORDER_MAX_PAY_COUNT_DEFAULT,
                SystemConfigKeyEnum.KS_ORDER_MAX_PAY_COUNT_DEFAULT,
                SystemConfigKeyEnum.ORDER_MAX_SUBMIT_COUNT_DEFAULT
                SystemConfigKeyEnum.ORDER_MAX_SUBMIT_COUNT_DEFAULT,
                SystemConfigKeyEnum.ALIPAY_KEY_VERIFY
        };
        for (SystemConfigKeyEnum key : keys) {
            String val = request.getParameter(key.getKey());
src/main/java/com/taoke/autopay/controller/client/OrderController.java
@@ -11,17 +11,16 @@
import com.taoke.autopay.entity.*;
import com.taoke.autopay.exception.KeyOrderException;
import com.taoke.autopay.exception.KeyVerifyException;
import com.taoke.autopay.exception.WxOrderCountException;
import com.taoke.autopay.factory.OrderFactory;
import com.taoke.autopay.service.*;
import com.taoke.autopay.utils.JsonUtil;
import com.taoke.autopay.utils.MoneyUtil;
import com.taoke.autopay.utils.StringUtil;
import com.taoke.autopay.utils.TimeUtil;
import com.taoke.autopay.utils.*;
import com.taoke.autopay.utils.order.DYOrderApi;
import com.taoke.autopay.vo.AcceptData;
import com.taoke.autopay.vo.KeyOrderVO;
import com.taoke.autopay.vo.OrderFilter;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +30,11 @@
import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @author hxh
@@ -204,6 +207,8 @@
                orderUpdate.setOrderState(dto.getOrder_status());
                orderUpdate.setOrderType(1);
                orderUpdate.setOrderNo(orderNo);
                orderUpdate.setOrderChannel(dto.getOrderChannel());
                orderUpdate.setPayType(Constant.PAY_TYPE_WITH_ORDER_NO);
                if (order.getState() == KeyOrder.STATE_NOT_PROCESS) {
                    if (dto.getOrder_status() == DYOrderDto.ORDER_STATUS_CANCELED) {
                        orderUpdate.setState(KeyOrder.STATE_PAY);
@@ -237,6 +242,8 @@
            orderUpdate.setOrderType(1);
            orderUpdate.setOrderState(dto.getOrder_status());
            orderUpdate.setOrderNo(orderNo);
            orderUpdate.setOrderChannel(dto.getOrderChannel());
            orderUpdate.setPayType(Constant.PAY_TYPE_WITH_ORDER_NO);
            orderUpdate.setExcutePayTime(new Date());
            keyOrderService.update(orderUpdate);
            order = keyOrderService.selectById(id);
@@ -276,21 +283,63 @@
            return JsonUtil.loadFalseResult("口令不存在");
        }
        money = money.replace("¥","");
        int orderType=Constant.ORDER_TYPE_UNKNOWN;
        if(orderNoDesc.contains("抖音")){
            orderType = Constant.ORDER_TYPE_DY;
        }else  if(orderNoDesc.contains("快手")){
            orderType = Constant.ORDER_TYPE_KS;
        }
        String orderNo= "";
        try {
            if(orderType==Constant.ORDER_TYPE_UNKNOWN){
                throw new KeyOrderException("未定义的订单类型");
            }
            if (!StringUtil.isNullOrEmpty(orderStatus)) {
                throw new KeyOrderException(orderStatus);
            }
            money = money.replace("¥","");
            // 匹配金额
           if(!MoneyUtil.getMoneyStr(order.getOrderMoney()).equalsIgnoreCase(money)){
               throw new KeyOrderException("金额不匹配");
           }
            DYOrderDto dyOrderDto =null;
            try {
                dyOrderDto = keyOrderService.verifyKey(orderNoDesc, orderStatus, money);
            }catch(KeyVerifyException ve){
                throw new KeyOrderException("口令验证失败:" + ve.getMessage());
            }
//            if(dyOrderDto!=null&&order.getOrderMoney()!=null){
//                // 判断订单支付金额与用户提交的金额是否匹配
//                if(dyOrderDto.getPay_amount()!=order.getOrderMoney().multiply(new BigDecimal(100)).setScale(0, RoundingMode.FLOOR).intValue()){
//                    throw new KeyOrderException(String.format("订单接口金额不匹配:%s-%s",dyOrderDto.getPay_amount(),MoneyUtil.getMoneyStr(order.getOrderMoney())));
//                }
//            }
            if(dyOrderDto!=null){
                orderNo = dyOrderDto.getOrder_id();
            }
            if (order.getUid() != null) {
                WxUserOrderCount countInfo = wxUserOrderCountService.get(order.getUid(), OrderCountTypeEnum.DY_ORDER_PAY, TimeUtil.getGernalTime(System.currentTimeMillis(), "yyyyMMdd"));
                OrderCountTypeEnum orderCountType=null;
                switch (orderType){
                    case Constant.ORDER_TYPE_DY:
                        orderCountType= OrderCountTypeEnum.DY_ORDER_PAY;
                        break;
                    case Constant.ORDER_TYPE_KS:
                        orderCountType= OrderCountTypeEnum.KS_ORDER_PAY;
                        break;
                }
                WxUserOrderCount countInfo = wxUserOrderCountService.get(order.getUid(), orderCountType, TimeUtil.getGernalTime(System.currentTimeMillis(), "yyyyMMdd"));
                if (countInfo != null) {
                    WxUserSettings settings = wxUserSettingService.getUserSettings(order.getUid());
                    if (settings.getDyOrderCountPerDay() <= countInfo.getOrderCount()) {
                        throw new Exception("今日已达支付次数上限:" + settings.getDyOrderCountPerDay());
                    int maxOrderCount = settings.getDyOrderCountPerDay();
                    if(orderCountType == OrderCountTypeEnum.KS_ORDER_PAY){
                        maxOrderCount = settings.getKsOrderCountPerDay();
                    }
                    if (maxOrderCount <= countInfo.getOrderCount()) {
                        throw new Exception("老铁今日已达支付次数上限:" + settings.getDyOrderCountPerDay());
                    }
                }
            }
@@ -298,7 +347,16 @@
            // 设置进入
            KeyOrder orderUpdate = new KeyOrder();
            orderUpdate.setId(id);
            orderUpdate.setOrderType(1);
            orderUpdate.setOrderType(orderType);
            orderUpdate.setOrderNo(orderNo);
            orderUpdate.setOrderMoney(new BigDecimal(money));
            if(dyOrderDto!=null){
                orderUpdate.setOrderState(dyOrderDto.getOrder_status());
                orderUpdate.setOrderChannel(dyOrderDto.getOrderChannel());
                orderUpdate.setPayType(Constant.PAY_TYPE_WITH_ORDER_NO);
            }else{
                orderUpdate.setPayType(Constant.PAY_TYPE_WITH_MONEY);
            }
            orderUpdate.setExcutePayTime(new Date());
            keyOrderService.update(orderUpdate);
            order = keyOrderService.selectById(id);
@@ -306,7 +364,9 @@
        } catch (KeyOrderException e) {
            KeyOrder orderUpdate = new KeyOrder();
            orderUpdate.setId(id);
            orderUpdate.setOrderType(1);
            orderUpdate.setOrderType(orderType);
            orderUpdate.setOrderNo(orderNo);
            orderUpdate.setOrderMoney(new BigDecimal(money));
            orderUpdate.setOrderState(0);
            orderUpdate.setState(KeyOrder.STATE_REJECT_PAY);
            if (order.getExcutePayTime() == null) {
@@ -325,7 +385,7 @@
    @ResponseBody
    @RequestMapping("setPayResult")
    public String setPayResult(AcceptData acceptData, String id, boolean paySuccess, String msg) {
        loggerPay.info("setPayResult: {}-{}", id, paySuccess);
        loggerPay.info("setPayResult: {}-{}-{}", id, paySuccess, msg);
        if (StringUtil.isNullOrEmpty(id)) {
            return JsonUtil.loadFalseResult("请上传id");
        }
@@ -333,22 +393,30 @@
        if (order == null) {
            return JsonUtil.loadFalseResult("口令不存在");
        }
        if (StringUtil.isNullOrEmpty(order.getOrderNo())) {
            return JsonUtil.loadFalseResult("没有匹配到订单号");
        }
//        if (StringUtil.isNullOrEmpty(order.getOrderNo())) {
//            return JsonUtil.loadFalseResult("没有匹配到订单号");
//        }
        if (order.getState() == KeyOrder.STATE_NOT_PROCESS) {
            if (!paySuccess) {
                // 支付失败
                KeyOrder orderUpdate = new KeyOrder();
                orderUpdate.setId(id);
                orderUpdate.setState(KeyOrder.STATE_NOT_PAY);
                orderUpdate.setStateDesc("支付失败");
                keyOrderService.update(orderUpdate);
                if(msg!=null&&msg.contains("超时"))
                {
                    loggerPay.info(String.format("因为超时支付失败不处理:%s-%s", order.getId(), msg));
                }else {
                    KeyOrder orderUpdate = new KeyOrder();
                    orderUpdate.setId(id);
                    orderUpdate.setState(KeyOrder.STATE_NOT_PAY);
                    orderUpdate.setStateDesc("支付失败");
                    keyOrderService.update(orderUpdate);
                }
                loggerPay.info("处理支付失败完成");
            } else {
                try {
                    keyOrderService.paySuccess(id, "支付成功", TimeUtil.getGernalTime(System.currentTimeMillis(), "yyyyMMdd"));
                    loggerPay.info("处理支付成功完成");
                } catch (WxOrderCountException e) {
                    loggerPay.error(e.getMessage());
                    e.printStackTrace();
                    return JsonUtil.loadFalseResult(e.getMessage());
                }
src/main/java/com/taoke/autopay/dao/KeyOrderMapper.java
@@ -35,6 +35,7 @@
        public Long uid;
        public Integer orderState;
        public Integer state;
        public Long agentId;
        public List<Integer> stateList;
        public String stateDesc;
        public Long distributeClientUid;
src/main/java/com/taoke/autopay/dao/agent/ChannelAgentMapper.java
New file
@@ -0,0 +1,41 @@
package com.taoke.autopay.dao.agent;
import java.lang.Integer;
import java.lang.String;
import java.util.Date;
import java.lang.Long;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.taoke.autopay.entity.agent.ChannelAgent;
import org.yeshi.utils.mybatis.BaseMapper;
public interface ChannelAgentMapper extends BaseMapper<ChannelAgent> {
    ChannelAgent selectByPrimaryKeyForUpdate(@Param("id") Long id);
    List<ChannelAgent> list(@Param("query") DaoQuery query);
    long count(@Param("query") DaoQuery query);
    public static class DaoQuery{
        public Long id;
        public String name;
        public String alias;
        public String account;
        public String pwd;
        public String alipayName;
        public String alipayAccount;
        public Date minAlipayUpdateTime;
        public Date maxAlipayUpdateTime;
        public Integer status;
        public String statusDesc;
        public Date minCreateTime;
        public Date maxCreateTime;
        public Date minUpdateTime;
        public Date maxUpdateTime;
        public long start;
        public int count;
        public List<String> sortList;
    }
}
src/main/java/com/taoke/autopay/dto/DYOrderDto.java
@@ -48,10 +48,9 @@
    private Long create_time;
    private String _create_time;
    private String source;
    private List<String> product_name;
    private List<String> order_type;
    private List<Integer> order_expire_time;
    private List<String> product_id_str;
    private List<DYSkuOrderDto> sku_order_list;
    private String orderChannel;
    public Long getApp_id() {
        return app_id;
@@ -157,35 +156,19 @@
        this.source = source;
    }
    public List<String> getProduct_name() {
        return product_name;
    public List<DYSkuOrderDto> getSku_order_list() {
        return sku_order_list;
    }
    public void setProduct_name(List<String> product_name) {
        this.product_name = product_name;
    public void setSku_order_list(List<DYSkuOrderDto> sku_order_list) {
        this.sku_order_list = sku_order_list;
    }
    public List<String> getOrder_type() {
        return order_type;
    public String getOrderChannel() {
        return orderChannel;
    }
    public void setOrder_type(List<String> order_type) {
        this.order_type = order_type;
    }
    public List<Integer> getOrder_expire_time() {
        return order_expire_time;
    }
    public void setOrder_expire_time(List<Integer> order_expire_time) {
        this.order_expire_time = order_expire_time;
    }
    public List<String> getProduct_id_str() {
        return product_id_str;
    }
    public void setProduct_id_str(List<String> product_id_str) {
        this.product_id_str = product_id_str;
    public void setOrderChannel(String orderChannel) {
        this.orderChannel = orderChannel;
    }
}
src/main/java/com/taoke/autopay/dto/DYSkuOrderDto.java
New file
@@ -0,0 +1,55 @@
package com.taoke.autopay.dto;
/**
 * @author hxh
 * @title: DYSkuOrderDto
 * @description: TODO
 * @date 2024/7/11 18:19
 */
public class DYSkuOrderDto {
    /**
     * sku_id : 3409297017495042
     * order_id : 6931934532492859095
     * pay_amount : 210
     * product_id : 3694557421864353931
     */
    private long sku_id;
    private String order_id;
    private int pay_amount;
    private long product_id;
    public long getSku_id() {
        return sku_id;
    }
    public void setSku_id(long sku_id) {
        this.sku_id = sku_id;
    }
    public String getOrder_id() {
        return order_id;
    }
    public void setOrder_id(String order_id) {
        this.order_id = order_id;
    }
    public int getPay_amount() {
        return pay_amount;
    }
    public void setPay_amount(int pay_amount) {
        this.pay_amount = pay_amount;
    }
    public long getProduct_id() {
        return product_id;
    }
    public void setProduct_id(long product_id) {
        this.product_id = product_id;
    }
}
src/main/java/com/taoke/autopay/dto/DYSubsidyDto.java
New file
@@ -0,0 +1,55 @@
package com.taoke.autopay.dto;
/**
 * @author hxh
 * @title: DYSubsidyDto
 * @description: TODO
 * @date 2024/7/11 18:22
 */
public class DYSubsidyDto {
    /**
     * goodsId : 3694557421864353931
     * goodsPrice : 210
     * subsidyAmount : 210
     * status : offLine
     */
    private String goodsId;
    private int goodsPrice;
    private int subsidyAmount;
    private String status;
    public String getGoodsId() {
        return goodsId;
    }
    public void setGoodsId(String goodsId) {
        this.goodsId = goodsId;
    }
    public int getGoodsPrice() {
        return goodsPrice;
    }
    public void setGoodsPrice(int goodsPrice) {
        this.goodsPrice = goodsPrice;
    }
    public int getSubsidyAmount() {
        return subsidyAmount;
    }
    public void setSubsidyAmount(int subsidyAmount) {
        this.subsidyAmount = subsidyAmount;
    }
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
}
src/main/java/com/taoke/autopay/dto/admin/OrderExcelDataDto.java
New file
@@ -0,0 +1,166 @@
package com.taoke.autopay.dto.admin;
import com.alibaba.excel.annotation.ExcelProperty;
/**
 * @author hxh
 * @title: OrderExcelDataDto
 * @description: 订单excel输出
 * @date 2024/7/18 22:44
 */
public class OrderExcelDataDto {
    @ExcelProperty("ID")
    private String id;
    @ExcelProperty("老铁ID")
    private Long uid;
    @ExcelProperty("口令")
    private String key;
    @ExcelProperty("口令提交时间")
    private String createTime;
    @ExcelProperty("是否支付成功")
    private String paySuccess;
    @ExcelProperty("状态简介")
    private String stateDesc;
    @ExcelProperty("订单金额")
    private String orderMoney;
    @ExcelProperty("支付时间")
    private String payTime;
    @ExcelProperty("支付方式")
    private String payType;
    @ExcelProperty("支付设备")
    private String payDevice;
    @ExcelProperty("订单号")
    private String orderNo;
    @ExcelProperty("订单渠道")
    private String orderChannel;
    @ExcelProperty("电商平台")
    private String platform;
    @ExcelProperty("总数")
    private int totalCount;
    @ExcelProperty("总金额")
    private String totalMoney;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public Long getUid() {
        return uid;
    }
    public void setUid(Long uid) {
        this.uid = uid;
    }
    public String getCreateTime() {
        return createTime;
    }
    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }
    public String getPaySuccess() {
        return paySuccess;
    }
    public void setPaySuccess(String paySuccess) {
        this.paySuccess = paySuccess;
    }
    public String getOrderMoney() {
        return orderMoney;
    }
    public void setOrderMoney(String orderMoney) {
        this.orderMoney = orderMoney;
    }
    public String getPayType() {
        return payType;
    }
    public void setPayType(String payType) {
        this.payType = payType;
    }
    public String getOrderNo() {
        return orderNo;
    }
    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }
    public String getOrderChannel() {
        return orderChannel;
    }
    public void setOrderChannel(String orderChannel) {
        this.orderChannel = orderChannel;
    }
    public int getTotalCount() {
        return totalCount;
    }
    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }
    public String getTotalMoney() {
        return totalMoney;
    }
    public void setTotalMoney(String totalMoney) {
        this.totalMoney = totalMoney;
    }
    public String getPlatform() {
        return platform;
    }
    public void setPlatform(String platform) {
        this.platform = platform;
    }
    public String getStateDesc() {
        return stateDesc;
    }
    public void setStateDesc(String stateDesc) {
        this.stateDesc = stateDesc;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getPayTime() {
        return payTime;
    }
    public void setPayTime(String payTime) {
        this.payTime = payTime;
    }
    public String getPayDevice() {
        return payDevice;
    }
    public void setPayDevice(String payDevice) {
        this.payDevice = payDevice;
    }
}
src/main/java/com/taoke/autopay/entity/KeyOrder.java
@@ -1,5 +1,6 @@
package com.taoke.autopay.entity;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.yeshi.utils.generater.mybatis.Column;
import org.yeshi.utils.generater.mybatis.Table;
@@ -13,6 +14,7 @@
 * @description: TODO
 * @date 2024/6/14 18:58
 */
@Data
@Table("table_order")
public class KeyOrder {
    // 尚未处理
@@ -56,124 +58,13 @@
    private Date payTime;
    @Column(name = "order_money")
    private BigDecimal orderMoney;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public Integer getOrderType() {
        return orderType;
    }
    public void setOrderType(Integer orderType) {
        this.orderType = orderType;
    }
    public String getOrderNo() {
        return orderNo;
    }
    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }
    public Integer getOrderState() {
        return orderState;
    }
    public void setOrderState(Integer orderState) {
        this.orderState = orderState;
    }
    public Integer getState() {
        return state;
    }
    public void setState(Integer state) {
        this.state = state;
    }
    public String getStateDesc() {
        return stateDesc;
    }
    public void setStateDesc(String stateDesc) {
        this.stateDesc = stateDesc;
    }
    public Long getDistributeClientUid() {
        return distributeClientUid;
    }
    public void setDistributeClientUid(Long distributeClientUid) {
        this.distributeClientUid = distributeClientUid;
    }
    public Date getDistributeTime() {
        return distributeTime;
    }
    public void setDistributeTime(Date distributeTime) {
        this.distributeTime = distributeTime;
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public Date getUpdateTime() {
        return updateTime;
    }
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
    public Long getUid() {
        return uid;
    }
    public void setUid(Long uid) {
        this.uid = uid;
    }
    public Date getExcutePayTime() {
        return excutePayTime;
    }
    public void setExcutePayTime(Date excutePayTime) {
        this.excutePayTime = excutePayTime;
    }
    public Date getPayTime() {
        return payTime;
    }
    public void setPayTime(Date payTime) {
        this.payTime = payTime;
    }
    public BigDecimal getOrderMoney() {
        return orderMoney;
    }
    public void setOrderMoney(BigDecimal orderMoney) {
        this.orderMoney = orderMoney;
    }
    @Column(name = "order_channel")
    private String orderChannel;
    @Column(name = "pay_type")
    private Integer payType;
    /**
     * 代理ID
     **/
    @Column(name = "agent_id")
    private Long agentId;
}
src/main/java/com/taoke/autopay/entity/OrderChannelEnum.java
New file
@@ -0,0 +1,36 @@
package com.taoke.autopay.entity;
/**
 * @author hxh
 * @title: OrderChannelEnum
 * @description: 订单渠道枚举
 * @date 2024/7/22 22:34
 */
public enum OrderChannelEnum {
    cyx("huohuo","超佣享"),
    bps("bps","爆品社"),
    unknown("unknown","卡金額")
    ;
    private String key;
    private String name;
    private OrderChannelEnum(String key, String name){
        this.key=key;
        this.name = name;
    }
    public String getKey() {
        return key;
    }
    public String getName() {
        return name;
    }
}
src/main/java/com/taoke/autopay/entity/SystemConfigKeyEnum.java
@@ -16,7 +16,9 @@
    KS_ORDER_MAX_PAY_COUNT_DEFAULT("ks_order_pay_count_default","快手订单最大默认付款次数"),
    ORDER_MAX_SUBMIT_COUNT_DEFAULT("order_submit_count_default","订单最大默认提交次数"),
    KEY_SUBMIT_TIME_RANGE("order_key_submit_time_range","订单口令提交时间段"),
    PAY_MONEY_LIST("pay_money_list","可支付金额列表")
    PAY_MONEY_LIST("pay_money_list","可支付金额列表"),
    ALIPAY_KEY_VERIFY("alipay_key_verify_state","是否需要提前验证支付宝口令"),
    ;
src/main/java/com/taoke/autopay/entity/agent/ChannelAgent.java
New file
@@ -0,0 +1,84 @@
package com.taoke.autopay.entity.agent;
import lombok.Builder;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.yeshi.utils.generater.mybatis.Column;
import org.yeshi.utils.generater.mybatis.Table;
import java.util.Date;
/**
 * @author hxh
 * @title: ChannelAgent
 * @description: 渠道代理
 * @date 2024/7/19 18:10
 */
@Data
@Builder
@Table("table_agent")
public class ChannelAgent {
    public final static int STATUS_NOMAL =0;
    public final static int STATUS_FORBIDDEN =1;
    /**
     * 代理ID
     */
    @Column(name = "_id")
    @Id
    private Long id;
    /**
     * 代理名称
     */
    @Column(name = "_name")
    private String name;
    /**
     * 代理标识
     */
    @Column(name = "_alias")
    private String alias;
    /**
     * 登录账号
     */
    @Column(name = "_account")
    private String account;
    /**
     * 登录密码
     */
    @Column(name = "_pwd")
    private String pwd;
    /**
     * 支付宝名称
     */
    @Column(name = "_alipay_name")
    private String alipayName;
    /**
     * 支付宝账号
     */
    @Column(name = "_alipay_account")
    private String alipayAccount;
    /**
     * 支付宝账号修改时间
     */
    @Column(name = "_alipay_update_time")
    private Date alipayUpdateTime;
    /**
     * 状态
     */
    @Column(name = "_status")
    private Integer status;
    /**
     * 状态简介
     */
    @Column(name = "_status_desc")
    private String statusDesc;
    @Column(name = "_create_time")
    private Date createTime;
    @Column(name = "_update_time")
    private Date updateTime;
}
src/main/java/com/taoke/autopay/entity/agent/ChannelAgentOrderRecord.java
New file
@@ -0,0 +1,44 @@
package com.taoke.autopay.entity.agent;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
 * @author hxh
 * @title: ChannelAgentOrderPayRecord
 * @description: 渠道订单支付记录
 * @date 2024/7/24 18:13
 */
@Data
public class ChannelAgentOrderRecord {
    private Long id;
    /**
     * 代理ID
     **/
    private Long agentId;
    /**
     * 日期
     **/
    private String day;
    /**
     * 提交的口令次数
     **/
    private Integer submitKeyCount;
    /**
     * 支付次数
     **/
    private Integer payCount;
    /**
     * 支付的金額
     **/
    private BigDecimal payMoney;
    private Date createTime;
    private Date updateTime;
}
src/main/java/com/taoke/autopay/entity/agent/ChannelAgentSettings.java
New file
@@ -0,0 +1,39 @@
package com.taoke.autopay.entity.agent;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
 * @author hxh
 * @title: ChannelAgentSettings
 * @description: 渠道设置
 * @date 2024/7/20 22:23
 */
@Data
public class ChannelAgentSettings {
    /**
     * 代理渠道ID
     */
  private Long id;
    /**
     * 渠道每天提交口令次数
     */
  private Long maxKeyCountPerDay;
    /**
     * 渠道每天支付的总金额
     */
  private BigDecimal maxPayMoneyPerDay;
  /**
   * 可提交口令的起始时间
   */
  private String startSubmitTime;
  /**
   * 可提交口令的结束时间
   */
  private String endSubmitTime;
  private Date createTime;
  private Date updateTime;
}
src/main/java/com/taoke/autopay/entity/agent/ChannelAgentSharingRatio.java
New file
@@ -0,0 +1,36 @@
package com.taoke.autopay.entity.agent;
import com.taoke.autopay.entity.OrderChannelEnum;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
 * @author hxh
 * @title: ChannelAgentSharingRatio
 * @description: 渠道代理分成比例设置
 * @date 2024/7/20 22:45
 */
@Data
public class ChannelAgentSharingRatio {
    private Long id;
    /**
     * 渠道ID
     **/
    private Long agengId;
    /**
     * 订单渠道
     **/
    private OrderChannelEnum orderChannel;
    /**
     * 分成比例
     **/
    private BigDecimal shareRatio;
    private Date createTime;
    private Date updateTime;
}
src/main/java/com/taoke/autopay/entity/agent/ChannelAgentWidthDrawRecord.java
New file
@@ -0,0 +1,44 @@
package com.taoke.autopay.entity.agent;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
 * @author hxh
 * @title: ChannelAgentWidthDrawRecord
 * @description: 渠道提现记录
 * @date 2024/7/20 22:06
 */
@Data
public class ChannelAgentWidthDrawRecord {
    private Long id;
    /**
     * 代理用户ID
     */
    private Long agentId;
    /**
     * 结算日期
     */
    private String settleDay;
    /**
     * 结算金额
     */
    private BigDecimal settleMoney;
    /**
     * 实际结算金额
     */
    private BigDecimal actualSettleMoney;
    /**
     * 支付时间
     */
    private Date payTime;
    private Date createTime;
    private Date updateTime;
}
src/main/java/com/taoke/autopay/exception/KeyVerifyException.java
New file
@@ -0,0 +1,29 @@
package com.taoke.autopay.exception;
/**
 * @author hxh
 * @title: LoginException
 * @description: 口令验证
 * @date 2024/6/14 18:46
 */
public class KeyVerifyException extends  Exception{
    public final static int CODE_COMMON = 1;
    public final static int CODE_ORDER_MONEY_NOT_MATCH = 10;
    public final static int CODE_KEY_MONEY_NOT_MATCH = 11;
    public final static int CODE_ORDER_STATUS_ERROR = 12;
    public final static int CODE_ORDER_TYPE_ERROR = 13;
    private int code;
    public int getCode() {
        return code;
    }
    public KeyVerifyException(int code, String msg){
        super(msg);
        this.code = code;
    }
}
src/main/java/com/taoke/autopay/service/KeyOrderService.java
@@ -1,8 +1,10 @@
package com.taoke.autopay.service;
import com.taoke.autopay.dao.KeyOrderMapper;
import com.taoke.autopay.dto.DYOrderDto;
import com.taoke.autopay.entity.KeyOrder;
import com.taoke.autopay.exception.KeyOrderException;
import com.taoke.autopay.exception.KeyVerifyException;
import com.taoke.autopay.exception.WxOrderCountException;
import com.taoke.autopay.vo.SubmitKeyInfo;
@@ -98,4 +100,17 @@
     **/
    public void deleteAll(Date maxCreateTime);
    /**
     * @author hxh
     * @description 验证口令
     * @date 20:38 2024/7/23
     * @param: id
     * @param: orderNoDesc
     * @param: orderStatus
     * @param: money
     * @return void
     **/
    public DYOrderDto verifyKey(String orderNoDesc, String orderStatus, String money) throws KeyVerifyException;
}
src/main/java/com/taoke/autopay/service/impl/KeyOrderServiceImpl.java
@@ -2,25 +2,28 @@
import com.taoke.autopay.dao.KeyOrderMapper;
import com.taoke.autopay.dao.WxUserSettingsMapper;
import com.taoke.autopay.entity.KeyOrder;
import com.taoke.autopay.entity.OrderCountTypeEnum;
import com.taoke.autopay.entity.OrderDistributeCountInfo;
import com.taoke.autopay.entity.WxUserSettings;
import com.taoke.autopay.dto.DYOrderDto;
import com.taoke.autopay.entity.*;
import com.taoke.autopay.exception.KeyOrderException;
import com.taoke.autopay.exception.KeyVerifyException;
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.utils.StringUtil;
import com.taoke.autopay.utils.TimeUtil;
import com.taoke.autopay.utils.*;
import com.taoke.autopay.utils.order.DYOrderApi;
import com.taoke.autopay.vo.SubmitKeyInfo;
import net.sf.json.JSONArray;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @author hxh
@@ -39,6 +42,9 @@
    @Resource
    private WxUserOrderCountService wxUserOrderCountService;
    @Resource
    private SystemConfigService systemConfigService;
    @Override
@@ -194,4 +200,68 @@
    public void deleteAll(Date maxCreateTime) {
        keyOrderMapper.deleteAll(maxCreateTime);
    }
    @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;
        }
        String orderNo= "";
        // 匹配连续的数字
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(orderNoDesc);
        while (matcher.find()) {
            // 获取匹配到的数字字符串
            String number = matcher.group();
            if (number.length() > 10) {
                orderNo = number;
                break;
            }
        }
            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() ));
                        }
                    }
                }else{
                    throw new KeyOrderException("抖音订单获取失败");
                }
            }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));
                }
            }
            return dyOrderDto;
    }
}
src/main/java/com/taoke/autopay/utils/AgentAliasUtil.java
New file
@@ -0,0 +1,39 @@
package com.taoke.autopay.utils;
/**
 * @author hxh
 * @title: AgentAliasUtil
 * @description: 代理标识工具
 * @date 2024/7/24 18:21
 */
public class AgentAliasUtil {
    private static final String BASE62_CHARACTERS = "ABCDEFabcdGHIJKLMqrstNO01234mnopu56789PQRSTUVWXYZefghijklvwxyz";
    private static String toBase62(long decimalNumber) {
        // 特殊情况:处理 0
        if (decimalNumber == 0) {
            return "0";
        }
        StringBuilder base62String = new StringBuilder();
        while (decimalNumber > 0) {
            int remainder = (int) (decimalNumber % 62);
            base62String.append(BASE62_CHARACTERS.charAt(remainder));
            decimalNumber /= 62;
        }
        // 由于我们是从低位到高位构建字符串,因此需要反转它
        return base62String.reverse().toString();
    }
    public static String createAlias(Long agentId ){
        return toBase62(System.currentTimeMillis()) + toBase62(agentId);
    }
    public static void main(String[]  args){
        System.out.println(createAlias(1L));
    }
}
src/main/java/com/taoke/autopay/utils/AlipayOrderUtil.java
New file
@@ -0,0 +1,195 @@
package com.taoke.autopay.utils;
import com.google.gson.Gson;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;
/**
 * @author hxh
 * @title: AlipayUtil
 * @description: 支付宝工具类
 * @date 2024/7/23 15:45
 */
public class AlipayOrderUtil {
    public static class AlipayOrderTradeInfo{
        public final static String STATUS_CANCELED = "BC";
        public final static String STATUS_PAY = "BS";
        public final static String STATUS_NOT_PAY = "BI";
        /**
         * bizIdentity : trade20001
         * bizNo : 2024072322001415961410745988
         * bizSuccessDate :
         * goodsQuantity : 1
         * goodsTitle : 抖音电商商家 即时到账--抖音电商-多笔订单6932448966275437765等
         * itemRealAmount : 29.90
         * salesProductCode : QUICK_MSECURITY_PAY
         * status : BC
         */
        private String bizIdentity;
        private String bizNo;
        private String bizSuccessDate;
        private int goodsQuantity;
        private String goodsTitle;
        private String itemRealAmount;
        private String salesProductCode;
        // BC: 订单已取消 BS: 订单已支付  BI: 订单未支付
        private String status;
        public String getBizIdentity() {
            return bizIdentity;
        }
        public void setBizIdentity(String bizIdentity) {
            this.bizIdentity = bizIdentity;
        }
        public String getBizNo() {
            return bizNo;
        }
        public void setBizNo(String bizNo) {
            this.bizNo = bizNo;
        }
        public String getBizSuccessDate() {
            return bizSuccessDate;
        }
        public void setBizSuccessDate(String bizSuccessDate) {
            this.bizSuccessDate = bizSuccessDate;
        }
        public int getGoodsQuantity() {
            return goodsQuantity;
        }
        public void setGoodsQuantity(int goodsQuantity) {
            this.goodsQuantity = goodsQuantity;
        }
        public String getGoodsTitle() {
            return goodsTitle;
        }
        public void setGoodsTitle(String goodsTitle) {
            this.goodsTitle = goodsTitle;
        }
        public String getItemRealAmount() {
            return itemRealAmount;
        }
        public void setItemRealAmount(String itemRealAmount) {
            this.itemRealAmount = itemRealAmount;
        }
        public String getSalesProductCode() {
            return salesProductCode;
        }
        public void setSalesProductCode(String salesProductCode) {
            this.salesProductCode = salesProductCode;
        }
        public String getStatus() {
            return status;
        }
        public void setStatus(String status) {
            this.status = status;
        }
    }
    private static Gson gson=JsonUtil.getSimpleGson();
    private static String getLocationUrl(String alipayUrl) throws IOException {
        Connection.Response response =  Jsoup.connect(alipayUrl)
                .userAgent("Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36")
                .timeout(20000)
                .header("Sec-Ch-Ua","\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"")
                .header("Sec-Ch-Ua-Mobile","?1")
                .header("Sec-Ch-Ua-Platform","\"Android\"")
                .header("Sec-Fetch-Dest","document")
                .header("Sec-Fetch-Mode","navigate")
                .header("Sec-Fetch-Site","none")
                .header("Sec-Fetch-User","?1")
                .followRedirects(false)
                .method(Connection.Method.GET)
                .execute();
        System.out.println(response.statusCode());
        if (response.statusCode() == 302 || response.statusCode() == 301) {
            // 获取重定向 URL
            String redirectUrl = response.header("Location");
            System.out.println("Redirect URL: " + redirectUrl);
            return redirectUrl;
        }
        return null;
    }
    private static AlipayOrderTradeInfo parseOrderInfo(String biz_no) throws Exception {
       String link = "https://mclient.alipay.com/h5/shareppyprepayconsult.htm?biz_no="+ URLEncoder.encode(biz_no,"UTF-8");
       Connection.Response response =  Jsoup.connect(link)
                .userAgent("Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36")
                .timeout(20000)
                .header("Sec-Ch-Ua","\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"")
                .header("Sec-Ch-Ua-Mobile","?1")
                .header("Sec-Ch-Ua-Platform","\"Android\"")
                .header("Sec-Fetch-Dest","document")
                .header("Sec-Fetch-Mode","navigate")
                .header("Sec-Fetch-Site","none")
                .header("Sec-Fetch-User","?1")
                .ignoreContentType(true)
                .method(Connection.Method.GET)
                .execute();
        if(response.statusCode()==200){
            String result =  response.body();
            System.out.println(result);
            JSONObject root =  JSONObject.fromObject(result);
            if(root.optBoolean("success")){
                JSONObject data = root.optJSONObject("data");
                if(data!=null){
                    JSONArray tradeInfoList =  data.optJSONArray("tradeInfoList");
                    if(tradeInfoList!=null&&tradeInfoList.size()>0){
                      return  gson.fromJson(tradeInfoList.optJSONObject(0).toString(),AlipayOrderTradeInfo.class);
                    }
                }
            }
            throw new Exception(result);
        }
        throw new Exception("网络请求出错");
    }
    public static AlipayOrderTradeInfo getTradeInfo(String url) throws Exception {
         url = getLocationUrl(url);
        if(url!=null){
            Map<String, String> params =  HttpUtil.getPramsFromUrl(url);
            AlipayOrderTradeInfo tradeInfo = parseOrderInfo(params.get("biz_no"));
            return tradeInfo;
        }
        return null;
    }
    public static void main(String[] args) throws Exception {
    String url = getLocationUrl("https://ur.alipay.com/_5MDnsPbo8TAsDNtNB9Tfia");
    if(url!=null){
        Map<String, String> params =  HttpUtil.getPramsFromUrl(url);
        AlipayOrderTradeInfo tradeInfo = parseOrderInfo(params.get("biz_no"));
        System.out.println("");
    }
//        parseOrderInfo("http://www.izxwl.com/admin/index.html");
    }
}
src/main/java/com/taoke/autopay/utils/Constant.java
@@ -14,8 +14,23 @@
    public final static String SESSION_KEY_TEMP_ALIPAY_KEY ="session_temp_alipay_key";
    public final static int ORDER_TYPE_UNKNOWN=0;
    public final static int ORDER_TYPE_DY=1;
    public final static int ORDER_TYPE_KS=2;
    public final static String ORDER_CHANNEL_CYX = "huohuo";
    public final static String ORDER_CHANNEL_BPS = "bps";
    // 根据订单号支付
    public final static int PAY_TYPE_WITH_ORDER_NO = 1;
    // 根据金额支付
    public final static int PAY_TYPE_WITH_MONEY = 2;
}
src/main/java/com/taoke/autopay/utils/HttpUtil.java
@@ -104,6 +104,29 @@
        return params;
    }
    public static String getUrlWithoutParams(String url) {
        if (url != null && url.indexOf("?") > -1) {
         return url.split("\\?")[0];
        }
        return url;
    }
    public static String getWholeUrl(String baseUrl,Map<String,String> params) {
        String url="";
        url+=baseUrl;
        if (url.indexOf("?") < 0){
            url+="?";
        }
        List<String> ps=new ArrayList<>();
        for(String k:params.keySet()){
            ps.add(k+ "=" + params.get(k));
        }
        url+=StringUtil.concat(ps,"&");
        return url;
    }
    public static String getHost(String host) {
        try {
            URL url = new URL(host);
src/main/java/com/taoke/autopay/utils/order/DYOrderApi.java
@@ -1,12 +1,24 @@
package com.taoke.autopay.utils.order;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.taoke.autopay.dto.DYOrderDto;
import com.taoke.autopay.dto.DYSkuOrderDto;
import com.taoke.autopay.dto.DYSubsidyDto;
import com.taoke.autopay.exception.KeyOrderException;
import com.taoke.autopay.utils.Constant;
import com.taoke.autopay.utils.HttpUtil;
import com.taoke.autopay.utils.JsonUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author hxh
@@ -17,27 +29,110 @@
public class DYOrderApi {
    private static Logger logger = LoggerFactory.getLogger("dyorderApiLogger");
    private static Gson gson=JsonUtil.getSimpleGson();
    private static String requestByOrderNo1(String orderNo) {
        String url = String.format("https://api.youihuo.com/open/order.getFreeOrder?apiKey=sTIFFTyunIFZfp5i4V6g19PN9biudl4v&orderId=%s", orderNo);
        String result = HttpUtil.get(url);
        System.out.println(result);
        return result;
    }
    public static DYOrderDto getOrderDetail(String orderNo) throws KeyOrderException {
    private static String requestByOrderNo2(String orderNo) {
        String url = String.format("https://api.bpshe.com/mall/douyinOMS/getSubsidyOrderInfo?orderId=%s", orderNo);
        Map<String,String> headers=new HashMap<>();
        headers.put("Accept","application/json;charset=utf-8");
        String result = HttpUtil.get(url, headers);
        return result;
    }
    private static DYOrderDto getOrderDetail1(String orderNo) throws KeyOrderException {
        String result = requestByOrderNo1(orderNo);
        System.out.println(result);
        JSONObject root = JSONObject.fromObject(result);
        if (root.optInt("code") != 1000) {
            logger.error(String.format("抖音订单查询出错:%s - %s",orderNo, result));
            logger.error(String.format("抖音订单查询出错(1):%s - %s",orderNo, result));
            throw new KeyOrderException(root.optString("message"));
        }
       JSONObject data = root.optJSONObject("data");
       return  JsonUtil.getSimpleGson().fromJson(data.toString(),DYOrderDto.class);
        JSONObject data = root.optJSONObject("data");
        DYOrderDto dto =  JsonUtil.getSimpleGson().fromJson(data.toString(),DYOrderDto.class);
        dto.setOrderChannel(Constant.ORDER_CHANNEL_CYX);
        return dto;
    }
    private static DYOrderDto getOrderDetail2(String orderNo) throws KeyOrderException {
        String result = requestByOrderNo2(orderNo);
        JSONObject root = JSONObject.fromObject(result);
        if (root.optInt("errCode") != 0) {
            logger.error(String.format("抖音订单查询出错(2):%s - %s",orderNo, result));
            throw new KeyOrderException(root.optString("errMsg"));
        }
        JSONObject data = root.optJSONObject("data");
        if(data==null){
            logger.error(String.format("抖音订单查询无数据(2):%s - %s",orderNo, result));
            throw new KeyOrderException("订单查询无数据");
        }
        JSONObject orderDetailData = data.optJSONObject("orderDetail");
        JSONArray subsidyDetailData = data.optJSONArray("subsidyDetail");
        if(orderDetailData==null||subsidyDetailData==null){
            logger.error(String.format("订单与补贴无数据(2):%s - %s",orderNo, result));
            throw new KeyOrderException("订单与补贴无数据");
        }
        orderDetailData = orderDetailData.optJSONObject("shop_order_detail");
        DYOrderDto dyOrder =   gson.fromJson(orderDetailData.toString(),DYOrderDto.class);
        List<DYSubsidyDto> subsidyList = gson.fromJson(subsidyDetailData.toString(), new TypeToken<List<DYSubsidyDto>>(){}.getType());
        if(subsidyList.size()!=dyOrder.getSku_order_list().size()){
            throw new KeyOrderException("订单商品与补贴商品不相等");
        }
        Map<String, DYSkuOrderDto> skuMap=new HashMap<>();
        for(DYSkuOrderDto d: dyOrder.getSku_order_list()){
            skuMap.put(d.getProduct_id()+"", d);
        }
        for(DYSubsidyDto d:subsidyList){
            if(skuMap.get(d.getGoodsId())==null){
                throw new KeyOrderException("补贴商品没在订单商品中");
            }
            if(skuMap.get(d.getGoodsId()).getPay_amount()> d.getSubsidyAmount()){
                throw new KeyOrderException("订单商品金额高于补贴金额");
            }
            if(!d.getStatus().equalsIgnoreCase("online")){
                throw new KeyOrderException("补贴下线");
            }
        }
        dyOrder.setOrderChannel(Constant.ORDER_CHANNEL_BPS);
        return  dyOrder;
    }
    public static DYOrderDto getOrderDetail(String orderNo) throws KeyOrderException {
        DYOrderDto dto=null;
        List<KeyOrderException> exceptions=new ArrayList<>();
        try {
            dto = getOrderDetail1(orderNo);
        }catch(KeyOrderException e){
            exceptions.add(e);
        }
        if(dto==null){
            try {
                dto = getOrderDetail2(orderNo);
            }catch(KeyOrderException e){
                exceptions.add(e);
            }
        }
        if(dto!=null){
            return dto;
        }
        String exception="";
        for(KeyOrderException e:exceptions){
            exception+=e.getMessage()+";";
        }
       throw new KeyOrderException(exception);
    }
    public static void main(String[] args) throws Exception {
        DYOrderDto dto = (DYOrderApi.getOrderDetail("6931373743528482165"));
        System.out.println("123123");
//        DYOrderDto dto = (DYOrderApi.getOrderDetail("6931373743528482165"));
        DYOrderDto result = getOrderDetail("6932498763822405300");
        System.out.println(result);
    }
}
src/main/java/com/taoke/autopay/vo/SubmitKeyInfo.java
@@ -12,6 +12,7 @@
    private String key;
    private String money;
    private String referer;
    public SubmitKeyInfo() {
    }
@@ -45,4 +46,12 @@
    public String toString() {
        return key+"-"+money;
    }
    public String getReferer() {
        return referer;
    }
    public void setReferer(String referer) {
        this.referer = referer;
    }
}
src/main/java/com/taoke/autopay/vo/admin/OrderSearchVO.java
New file
@@ -0,0 +1,38 @@
package com.taoke.autopay.vo.admin;
/**
 * @author hxh
 * @title: OrderSearchVO
 * @description: 订单搜索
 * @date 2024/7/18 22:33
 */
public class OrderSearchVO {
    private String key;
    private String startDate;
    private String endDate;
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getStartDate() {
        return startDate;
    }
    public void setStartDate(String startDate) {
        this.startDate = startDate;
    }
    public String getEndDate() {
        return endDate;
    }
    public void setEndDate(String endDate) {
        this.endDate = endDate;
    }
}
src/main/resources/application.yml
@@ -1,3 +1,3 @@
spring:
  profiles:
    active: dev
    active: pro
src/main/resources/mapper/ChannelAgentMapper.xml
New file
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.taoke.autopay.dao.agent.ChannelAgentMapper">
  <resultMap id="BaseResultMap" type="com.taoke.autopay.entity.agent.ChannelAgent">
    <id column="_id" property="id" jdbcType="BIGINT"/>
    <result column="_name" property="name" jdbcType="VARCHAR"/>
    <result column="_alias" property="alias" jdbcType="VARCHAR"/>
    <result column="_account" property="account" jdbcType="VARCHAR"/>
    <result column="_pwd" property="pwd" jdbcType="VARCHAR"/>
    <result column="_alipay_name" property="alipayName" jdbcType="VARCHAR"/>
    <result column="_alipay_account" property="alipayAccount" jdbcType="VARCHAR"/>
    <result column="_alipay_update_time" property="alipayUpdateTime" jdbcType="TIMESTAMP"/>
    <result column="_status" property="status" jdbcType="INTEGER"/>
    <result column="_status_desc" property="statusDesc" jdbcType="VARCHAR"/>
    <result column="_create_time" property="createTime" jdbcType="TIMESTAMP"/>
    <result column="_update_time" property="updateTime" jdbcType="TIMESTAMP"/>
  </resultMap>
  <sql id="Base_Column_List">_id,_name,_alias,_account,_pwd,_alipay_name,_alipay_account,_alipay_update_time,_status,_status_desc,_create_time,_update_time</sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long">select
    <include refid="Base_Column_List"/> from table_agent where _id = #{id,jdbcType=BIGINT}
  </select>
  <select id="selectByPrimaryKeyForUpdate" resultMap="BaseResultMap" parameterType="java.lang.Long">select
    <include refid="Base_Column_List"/> from table_agent where _id = #{id,jdbcType=BIGINT} for update
  </select>
  <sql id="listWhereSQL">
    <if test="query.id!=null">AND _id = #{query.id}</if>
    <if test="query.name!=null">AND _name = #{query.name}</if>
    <if test="query.alias!=null">AND _alias = #{query.alias}</if>
    <if test="query.account!=null">AND _account = #{query.account}</if>
    <if test="query.pwd!=null">AND _pwd = #{query.pwd}</if>
    <if test="query.alipayName!=null">AND _alipay_name = #{query.alipayName}</if>
    <if test="query.alipayAccount!=null">AND _alipay_account = #{query.alipayAccount}</if>
    <if test="query.minAlipayUpdateTime!=null">AND _alipay_update_time >= #{query.minAlipayUpdateTime}</if>
    <if test="query.maxAlipayUpdateTime!=null">AND #{query.maxAlipayUpdateTime} > _alipay_update_time</if>
    <if test="query.status!=null">AND _status = #{query.status}</if>
    <if test="query.statusDesc!=null">AND _status_desc = #{query.statusDesc}</if>
    <if test="query.minCreateTime!=null">AND _create_time >= #{query.minCreateTime}</if>
    <if test="query.maxCreateTime!=null">AND #{query.maxCreateTime} > _create_time</if>
    <if test="query.minUpdateTime!=null">AND _update_time >= #{query.minUpdateTime}</if>
    <if test="query.maxUpdateTime!=null">AND #{query.maxUpdateTime} > _update_time</if>
  </sql>
  <select id="list" resultMap="BaseResultMap">select
    <include refid="Base_Column_List"/> from table_agent where 1=1
    <include refid="listWhereSQL"/>
    <if test="query.sortList!=null">
      <foreach collection="query.sortList" item="item" open=" order by " separator=",">#{item}</foreach>
    </if>limit #{query.start},#{query.count}
  </select>
  <select id="count" resultType="java.lang.Long">select count(*) from table_agent where 1=1
    <include refid="listWhereSQL"/>
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">delete from table_agent where _id = #{id,jdbcType=BIGINT}</delete>
  <insert id="insert" parameterType="com.taoke.autopay.entity.agent.ChannelAgent" useGeneratedKeys="true" keyProperty="id">insert into table_agent (_id,_name,_alias,_account,_pwd,_alipay_name,_alipay_account,_alipay_update_time,_status,_status_desc,_create_time,_update_time) values (#{id,jdbcType=BIGINT},#{name,jdbcType=VARCHAR},#{alias,jdbcType=VARCHAR},#{account,jdbcType=VARCHAR},#{pwd,jdbcType=VARCHAR},#{alipayName,jdbcType=VARCHAR},#{alipayAccount,jdbcType=VARCHAR},#{alipayUpdateTime,jdbcType=TIMESTAMP},#{status,jdbcType=INTEGER},#{statusDesc,jdbcType=VARCHAR},#{createTime,jdbcType=TIMESTAMP},#{updateTime,jdbcType=TIMESTAMP})</insert>
  <insert id="insertSelective" parameterType="com.taoke.autopay.entity.agent.ChannelAgent" useGeneratedKeys="true" keyProperty="id">insert into table_agent
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">_id,</if>
      <if test="name != null">_name,</if>
      <if test="alias != null">_alias,</if>
      <if test="account != null">_account,</if>
      <if test="pwd != null">_pwd,</if>
      <if test="alipayName != null">_alipay_name,</if>
      <if test="alipayAccount != null">_alipay_account,</if>
      <if test="alipayUpdateTime != null">_alipay_update_time,</if>
      <if test="status != null">_status,</if>
      <if test="statusDesc != null">_status_desc,</if>
      <if test="createTime != null">_create_time,</if>
      <if test="updateTime != null">_update_time,</if>
    </trim>values
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">#{id,jdbcType=BIGINT},</if>
      <if test="name != null">#{name,jdbcType=VARCHAR},</if>
      <if test="alias != null">#{alias,jdbcType=VARCHAR},</if>
      <if test="account != null">#{account,jdbcType=VARCHAR},</if>
      <if test="pwd != null">#{pwd,jdbcType=VARCHAR},</if>
      <if test="alipayName != null">#{alipayName,jdbcType=VARCHAR},</if>
      <if test="alipayAccount != null">#{alipayAccount,jdbcType=VARCHAR},</if>
      <if test="alipayUpdateTime != null">#{alipayUpdateTime,jdbcType=TIMESTAMP},</if>
      <if test="status != null">#{status,jdbcType=INTEGER},</if>
      <if test="statusDesc != null">#{statusDesc,jdbcType=VARCHAR},</if>
      <if test="createTime != null">#{createTime,jdbcType=TIMESTAMP},</if>
      <if test="updateTime != null">#{updateTime,jdbcType=TIMESTAMP},</if>
    </trim>
  </insert>
  <update id="updateByPrimaryKey" parameterType="com.taoke.autopay.entity.agent.ChannelAgent">update table_agent set _name = #{name,jdbcType=VARCHAR},_alias = #{alias,jdbcType=VARCHAR},_account = #{account,jdbcType=VARCHAR},_pwd = #{pwd,jdbcType=VARCHAR},_alipay_name = #{alipayName,jdbcType=VARCHAR},_alipay_account = #{alipayAccount,jdbcType=VARCHAR},_alipay_update_time = #{alipayUpdateTime,jdbcType=TIMESTAMP},_status = #{status,jdbcType=INTEGER},_status_desc = #{statusDesc,jdbcType=VARCHAR},_create_time = #{createTime,jdbcType=TIMESTAMP},_update_time = #{updateTime,jdbcType=TIMESTAMP} where _id = #{id,jdbcType=BIGINT}</update>
  <update id="updateByPrimaryKeySelective" parameterType="com.taoke.autopay.entity.agent.ChannelAgent">update table_agent
    <set>
      <if test="name != null">_name=#{name,jdbcType=VARCHAR},</if>
      <if test="alias != null">_alias=#{alias,jdbcType=VARCHAR},</if>
      <if test="account != null">_account=#{account,jdbcType=VARCHAR},</if>
      <if test="pwd != null">_pwd=#{pwd,jdbcType=VARCHAR},</if>
      <if test="alipayName != null">_alipay_name=#{alipayName,jdbcType=VARCHAR},</if>
      <if test="alipayAccount != null">_alipay_account=#{alipayAccount,jdbcType=VARCHAR},</if>
      <if test="alipayUpdateTime != null">_alipay_update_time=#{alipayUpdateTime,jdbcType=TIMESTAMP},</if>
      <if test="status != null">_status=#{status,jdbcType=INTEGER},</if>
      <if test="statusDesc != null">_status_desc=#{statusDesc,jdbcType=VARCHAR},</if>
      <if test="createTime != null">_create_time=#{createTime,jdbcType=TIMESTAMP},</if>
      <if test="updateTime != null">_update_time=#{updateTime,jdbcType=TIMESTAMP},</if>
    </set> where _id = #{id,jdbcType=BIGINT}
  </update>
</mapper>
src/main/resources/mapper/KeyOrderMapper.xml
@@ -16,14 +16,17 @@
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>  
    <result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>  
    <result column="excute_pay_time" property="excutePayTime" jdbcType="TIMESTAMP"/>  
    <result column="pay_time" property="payTime" jdbcType="TIMESTAMP"/>
    <result column="order_money" property="orderMoney" jdbcType="DECIMAL"/>
    <result column="pay_time" property="payTime" jdbcType="TIMESTAMP"/>
    <result column="order_money" property="orderMoney" jdbcType="DECIMAL"/>
    <result column="order_channel" property="orderChannel" jdbcType="VARCHAR"/>
    <result column="pay_type" property="payType" jdbcType="INTEGER"/>
    <result column="agent_id" property="agentId" jdbcType="BIGINT"/>
  </resultMap>  
  <resultMap id="DistributeResultMap" type="com.taoke.autopay.entity.OrderDistributeCountInfo"> 
    <result column="uid" property="uid" jdbcType="BIGINT"/>  
    <result column="count" property="count" jdbcType="INTEGER"/> 
  </resultMap>  
  <sql id="Base_Column_List">id,uid,`key`,order_type,order_no,order_state,state,state_desc,distribute_client_uid,distribute_time,create_time,update_time,excute_pay_time,pay_time,order_money</sql>
  <sql id="Base_Column_List">id,uid,`key`,order_type,order_no,order_state,state,state_desc,distribute_client_uid,distribute_time,create_time,update_time,excute_pay_time,pay_time,order_money,order_channel,pay_type,agent_id</sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long">select 
    <include refid="Base_Column_List"/> from table_order where id = #{id,jdbcType=BIGINT}
  </select>  
@@ -40,7 +43,8 @@
    <if test="query.orderType!=null">AND order_type = #{query.orderType}</if>  
    <if test="query.orderNo!=null">AND order_no = #{query.orderNo}</if>  
    <if test="query.orderState!=null">AND order_state = #{query.orderState}</if>  
    <if test="query.state!=null">AND state = #{query.state}</if>
    <if test="query.state!=null">AND state = #{query.state}</if>
    <if test="query.agentId!=null">AND agent_id = #{query.agentId}</if>
    <if test="query.stateList!=null"> 
      <foreach collection="query.stateList" item="state" separator=" or " open=" AND (" close=") ">state = #{state}</foreach> 
    </if>  
@@ -51,7 +55,7 @@
    <if test="query.minCreateTime!=null">AND create_time &gt;= #{query.minCreateTime}</if>  
    <if test="query.maxCreateTime!=null">AND #{query.maxCreateTime} &gt; create_time</if>  
    <if test="query.minUpdateTime!=null">AND update_time &gt;= #{query.minUpdateTime}</if>  
    <if test="query.maxUpdateTime!=null">AND #{query.maxUpdateTime} &gt; update_time</if>
    <if test="query.maxUpdateTime!=null">AND #{query.maxUpdateTime} &gt; update_time</if>
  </sql>  
  <select id="list" resultMap="BaseResultMap">select 
    <include refid="Base_Column_List"/> from table_order where 1=1 
@@ -64,7 +68,7 @@
    <include refid="listWhereSQL"/> 
  </select>  
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">delete from table_order where id = #{id,jdbcType=BIGINT}</delete>  
  <insert id="insert" parameterType="com.taoke.autopay.entity.KeyOrder" useGeneratedKeys="true" keyProperty="id">insert into table_order (id,uid,key,order_type,order_no,order_state,state,state_desc,distribute_client_uid,distribute_time,create_time,update_time,id,excute_pay_time,pay_time,order_money) values (#{id,jdbcType=VARCHAR},#{uid,jdbcType=BIGINT},#{key,jdbcType=VARCHAR},#{orderType,jdbcType=INTEGER},#{orderNo,jdbcType=VARCHAR},#{orderState,jdbcType=INTEGER},#{state,jdbcType=INTEGER},#{stateDesc,jdbcType=VARCHAR},#{distributeClientUid,jdbcType=BIGINT},#{distributeTime,jdbcType=TIMESTAMP},#{createTime,jdbcType=TIMESTAMP},#{updateTime,jdbcType=TIMESTAMP},#{id,jdbcType=VARCHAR},#{excutePayTime,jdbcType=TIMESTAMP},#{payTime,jdbcType=TIMESTAMP},#{orderMoney,jdbcType=DECIMAL})</insert>
  <insert id="insert" parameterType="com.taoke.autopay.entity.KeyOrder" useGeneratedKeys="true" keyProperty="id">insert into table_order (id,uid,key,order_type,order_no,order_state,state,state_desc,distribute_client_uid,distribute_time,create_time,update_time,id,excute_pay_time,pay_time,order_money,order_channel,pay_type,agent_id) values (#{id,jdbcType=VARCHAR},#{uid,jdbcType=BIGINT},#{key,jdbcType=VARCHAR},#{orderType,jdbcType=INTEGER},#{orderNo,jdbcType=VARCHAR},#{orderState,jdbcType=INTEGER},#{state,jdbcType=INTEGER},#{stateDesc,jdbcType=VARCHAR},#{distributeClientUid,jdbcType=BIGINT},#{distributeTime,jdbcType=TIMESTAMP},#{createTime,jdbcType=TIMESTAMP},#{updateTime,jdbcType=TIMESTAMP},#{id,jdbcType=VARCHAR},#{excutePayTime,jdbcType=TIMESTAMP},#{payTime,jdbcType=TIMESTAMP},#{orderMoney,jdbcType=DECIMAL},#{orderChannel,jdbcType=VARCHAR},#{payType,jdbcType=INTEGER},#{agentId,jdbcType=BIGINT})</insert>
  <insert id="insertSelective" parameterType="com.taoke.autopay.entity.KeyOrder" useGeneratedKeys="true" keyProperty="id">insert into table_order 
    <trim prefix="(" suffix=")" suffixOverrides=","> 
      <if test="id != null">id,</if>  
@@ -81,7 +85,10 @@
      <if test="updateTime != null">update_time,</if>  
      <if test="excutePayTime != null">excute_pay_time,</if>  
      <if test="payTime != null">pay_time,</if>  
      <if test="orderMoney != null">order_money,</if>
      <if test="orderMoney != null">order_money,</if>
      <if test="orderChannel != null">order_channel,</if>
      <if test="payType != null">pay_type,</if>
      <if test="agentId != null">agent_id,</if>
    </trim>values 
    <trim prefix="(" suffix=")" suffixOverrides=","> 
      <if test="id != null">#{id,jdbcType=VARCHAR},</if>  
@@ -96,12 +103,15 @@
      <if test="distributeTime != null">#{distributeTime,jdbcType=TIMESTAMP},</if>  
      <if test="createTime != null">#{createTime,jdbcType=TIMESTAMP},</if>  
      <if test="updateTime != null">#{updateTime,jdbcType=TIMESTAMP},</if>  
      <if test="excutePayTime != null">#{excutePayTime,jdbcType=TIMESTAMP}</if>
      <if test="payTime != null">#{payTime,jdbcType=TIMESTAMP}</if>
      <if test="orderMoney != null">#{orderMoney,jdbcType=DECIMAL}</if>
      <if test="excutePayTime != null">#{excutePayTime,jdbcType=TIMESTAMP},</if>
      <if test="payTime != null">#{payTime,jdbcType=TIMESTAMP},</if>
      <if test="orderMoney != null">#{orderMoney,jdbcType=DECIMAL},</if>
      <if test="orderChannel != null">#{orderChannel,jdbcType=VARCHAR},</if>
      <if test="payType != null">#{payType,jdbcType=INTEGER},</if>
      <if test="agentId != null">#{agentId,jdbcType=BIGINT},</if>
    </trim> 
  </insert>  
  <update id="updateByPrimaryKey" parameterType="com.taoke.autopay.entity.KeyOrder">update table_order set uid = #{uid,jdbcType=BIGINT},`key` = #{key,jdbcType=VARCHAR},order_type = #{orderType,jdbcType=INTEGER},order_no = #{orderNo,jdbcType=VARCHAR},order_state = #{orderState,jdbcType=INTEGER},state = #{state,jdbcType=INTEGER},state_desc = #{stateDesc,jdbcType=VARCHAR},distribute_client_uid = #{distributeClientUid,jdbcType=BIGINT},distribute_time = #{distributeTime,jdbcType=TIMESTAMP},create_time = #{createTime,jdbcType=TIMESTAMP},update_time = #{updateTime,jdbcType=TIMESTAMP} ,excute_pay_time =#{excutePayTime,jdbcType=TIMESTAMP}, pay_time =#{payTime,jdbcType=TIMESTAMP} ,order_money =#{orderMoney,jdbcType=DECIMAL}, where id = #{id,jdbcType=VARCHAR}</update>
  <update id="updateByPrimaryKey" parameterType="com.taoke.autopay.entity.KeyOrder">update table_order set uid = #{uid,jdbcType=BIGINT},`key` = #{key,jdbcType=VARCHAR},order_type = #{orderType,jdbcType=INTEGER},order_no = #{orderNo,jdbcType=VARCHAR},order_state = #{orderState,jdbcType=INTEGER},state = #{state,jdbcType=INTEGER},state_desc = #{stateDesc,jdbcType=VARCHAR},distribute_client_uid = #{distributeClientUid,jdbcType=BIGINT},distribute_time = #{distributeTime,jdbcType=TIMESTAMP},create_time = #{createTime,jdbcType=TIMESTAMP},update_time = #{updateTime,jdbcType=TIMESTAMP} ,excute_pay_time =#{excutePayTime,jdbcType=TIMESTAMP}, pay_time =#{payTime,jdbcType=TIMESTAMP} ,order_money =#{orderMoney,jdbcType=DECIMAL}, order_channel =#{orderChannel,jdbcType=VARCHAR}, pay_type =#{payType,jdbcType=INTEGER}, agent_id =#{agentId,jdbcType=BIGINT}, where id = #{id,jdbcType=VARCHAR}</update>
  <update id="updateByPrimaryKeySelective" parameterType="com.taoke.autopay.entity.KeyOrder">update table_order 
    <set> 
      <if test="uid != null">uid=#{uid,jdbcType=BIGINT},</if>  
@@ -116,11 +126,14 @@
      <if test="createTime != null">create_time=#{createTime,jdbcType=TIMESTAMP},</if>  
      <if test="updateTime != null">update_time=#{updateTime,jdbcType=TIMESTAMP},</if>  
      <if test="excutePayTime !=null">excute_pay_time =#{excutePayTime,jdbcType=TIMESTAMP},</if>  
      <if test="payTime !=null">pay_time =#{payTime,jdbcType=TIMESTAMP},</if>
      <if test="orderMoney !=null">order_money =#{orderMoney,jdbcType=DECIMAL},</if>
      <if test="payTime !=null">pay_time =#{payTime,jdbcType=TIMESTAMP},</if>
      <if test="orderMoney !=null">order_money =#{orderMoney,jdbcType=DECIMAL},</if>
      <if test="orderChannel !=null">order_channel =#{orderChannel,jdbcType=VARCHAR},</if>
      <if test="payType !=null">pay_type =#{payType,jdbcType=INTEGER},</if>
      <if test="agentId !=null">agent_id =#{agentId,jdbcType=BIGINT},</if>
    </set> where id = #{id,jdbcType=VARCHAR}
  </update>  
  <select id="listDistributeUids" resultMap="DistributeResultMap" >SELECT u.`id` as uid, IF( a.count IS NULL,0,a.count) AS `count` FROM `table_user` u LEFT JOIN (SELECT o.`distribute_client_uid` AS uid,COUNT(*) AS `count` FROM `table_order` o WHERE o.`state` = 0 and  create_time > #{minKeyOrderCreateTime} GROUP BY o.`distribute_client_uid`) a ON a.uid = u.`id` WHERE rule=0
  <select id="listDistributeUids" resultMap="DistributeResultMap">SELECT u.`id` as uid, IF( a.count IS NULL,0,a.count) AS `count` FROM `table_user` u LEFT JOIN (SELECT o.`distribute_client_uid` AS uid,COUNT(*) AS `count` FROM `table_order` o WHERE o.`state` = 0 and create_time &gt; #{minKeyOrderCreateTime} GROUP BY o.`distribute_client_uid`) a ON a.uid = u.`id` WHERE rule=0
    <if test="minActiveTime!=null">and active_time &gt;=#{minActiveTime}</if> 
  </select>  
  <select id="listNotDistributed" resultMap="BaseResultMap">select 
src/main/resources/static/admin/order-list.html
@@ -21,7 +21,18 @@
                        <input type="text" name="key" id="key" placeholder="老铁ID/订单号搜索" autocomplete="off"
                            class="layui-input">
                    </div>
                    <div class="layui-inline">
                        <input type="text" name="startDate"  placeholder="开始时间" autocomplete="off"
                               class="layui-input">
                    </div>
                    <div class="layui-inline">
                        <input type="text" name="endDate"  placeholder="结束时间" autocomplete="off"
                               class="layui-input">
                    </div>
                    <button class="layui-btn layui-btn-normal" lay-submit lay-filter="search" id="search">搜索</button>
                    <button class="layui-btn layui-btn-normal layui-btn-xs" lay-submit lay-filter="download" id="download">下载</button>
                </div>
            </form>
            <div class="layui-form" id="table-list">
@@ -39,10 +50,24 @@
                // TODO 跳转到老铁ID                
            }
            layui.use(['form', 'jquery', 'layer', 'table'], function() {
            layui.use(['form', 'jquery', 'layer', 'table','laydate'], function() {
                var table = layui.table;
                var form = layui.form;
                var $ = layui.jquery;
                var  laydate = layui.laydate;
                laydate.render({
                    elem: "input[name=startDate]",
                    type: "date",
                    value: new Date(),
                    isInitValue:false
                });
                laydate.render({
                    elem: "input[name=endDate]",
                    type: "date",
                    value: new Date(),
                    isInitValue:false
                });
                
                let table_option = {
                    elem: '#table',
@@ -203,6 +228,14 @@
                    return false;
                });
                form.on('submit(download)', function(data) {
                    var href ="/admin/api/order/downLoadOrder?"
                    for(var k in data.field){
                        href+=(k+"="+encodeURIComponent(data.field[k])+"&")
                    }
                    window.open(href, '_blank');
                    return false;
                });
            });
        </script>
    </body>
src/main/resources/static/admin/pay_settings.html
@@ -127,6 +127,9 @@
                            for(var i=0;i<response.data.moneys.length;i++){
                                laytpl($('#payMoneyTemplate').html()).render({"index": i+1, "label":"金额"+ (i+1),"money":response.data.moneys[i]}, function(html){
                                                        $("#add").parent().parent().before(html);
                                                        $(".delete").bind("click",function(e){
                                                                             $(e.target).parent().parent().remove();
                                                        });
                                });
                            }
                        } else {
src/main/resources/static/admin/settings_edit.html
@@ -45,6 +45,13 @@
                        placeholder="总频次限制" autocomplete="off" class="layui-input">
                </div>
            </div>
            <div class="layui-form-item">
                <label class="layui-form-label">是否提前验证支付宝口令</label>
                <div class="layui-input-block">
                          <input type="checkbox" name="alipay_key_verify_state" value="1" lay-skin="switch">
                </div>
            </div>
            <div class="layui-input-block">
                <button class="layui-btn layui-btn-normal" lay-submit lay-filter="sure" id="sure">确定</button>
@@ -74,6 +81,9 @@
                    function(response) {
                        layer.close(index);
                        if (response.code == 0) {
                            if(parseInt(response.data.alipay_key_verify_state)<1){
                              delete response.data.alipay_key_verify_state;
                            }
                            form.val("edit", response.data);
                        } else {
                            layer.msg(response.msg);
@@ -86,7 +96,13 @@
                //监听提交
                form.on('submit(sure)', function(data) {
                    $.post("/admin/api/settings/setDefaultOrderCount", data.field,
                    var params = data.field;
                    if(params.alipay_key_verify_state==undefined){
                        params.alipay_key_verify_state = "0";
                    }
                    console.log(params);
                    $.post("/admin/api/settings/setDefaultOrderCount", params,
                        function(response) {
                            if (response.code == 0) {
                                layer.msg("修改成功");
src/main/resources/static/index2.html
@@ -25,6 +25,7 @@
                border-radius: 0.5rem;
                width: 80%;
                margin-top: 2rem;
                display: none;
            }
            
            .btn{
@@ -79,11 +80,11 @@
                        layer.msg("请输入口令");
                        return;
                    }
                    const moneyRegex = /^\d+(\.\d{1,2})?$/;
                    if (!moneyRegex.test(money)) {
                        layer.msg("付款金额输入错误");
                        return;
                    }
                    // const moneyRegex = /^\d+(\.\d{1,2})?$/;
                    // if (!moneyRegex.test(money)) {
                    //     layer.msg("付款金额输入错误");
                    //     return;
                    // }
                    var index = layer.load();
                    // 上传口令
                    $.post("/webapi/submitKeyV3",{"key":text,"money": money},function(response){
src/test/java/com/taoke/autopay/AutopayApplicationTests.java
@@ -3,6 +3,8 @@
import com.taoke.autopay.dao.ClientInfoMapper;
import com.taoke.autopay.dao.KeyOrderMapper;
import com.taoke.autopay.entity.ClientInfo;
import com.taoke.autopay.entity.KeyOrder;
import com.taoke.autopay.entity.OrderCountTypeEnum;
import com.taoke.autopay.entity.OrderDistributeCountInfo;
import com.taoke.autopay.exception.KeyOrderException;
import com.taoke.autopay.service.ClientInfoService;
@@ -58,6 +60,24 @@
    }
    @Test
    void testOrder(){
        String id="63f06977c49d0c5ec2b4c556010cea4b";
        KeyOrder old = keyOrderMapper.selectByPrimaryKeyForUpdate(id);
        if(old==null){
            return;
        }
        KeyOrder orderUpdate = new KeyOrder();
        orderUpdate.setId(id);
        orderUpdate.setState(KeyOrder.STATE_PAY);
        orderUpdate.setStateDesc("支付成功");
        if(old.getPayTime()==null){
            orderUpdate.setPayTime(new Date());
        }
        keyOrderService.update(orderUpdate);
    }
    @Test
    void contextLoads() {
        ClientInfo info = new ClientInfo();
        info.setName("超级管理员");
src/test/java/com/taoke/autopay/KeyTest.java
New file
@@ -0,0 +1,94 @@
package com.taoke.autopay;
import com.taoke.autopay.dto.DYOrderDto;
import com.taoke.autopay.entity.KeyOrder;
import com.taoke.autopay.entity.SystemConfigKeyEnum;
import com.taoke.autopay.exception.KeyOrderException;
import com.taoke.autopay.exception.KeyVerifyException;
import com.taoke.autopay.exception.WxOrderCountException;
import com.taoke.autopay.service.KeyOrderService;
import com.taoke.autopay.service.SystemConfigService;
import com.taoke.autopay.utils.AlipayOrderUtil;
import com.taoke.autopay.utils.TimeUtil;
import com.taoke.autopay.vo.SubmitKeyInfo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.yeshi.utils.UrlUtils;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
 * @author hxh
 * @title: KeyTest
 * @description: TODO
 * @date 2024/7/24 6:56
 */
@SpringBootTest
public class KeyTest {
    @Resource
    private SystemConfigService systemConfigService;
    @Resource
    private KeyOrderService keyOrderService;
    private void addKey(SubmitKeyInfo keyInfo, Long wxUid) throws KeyVerifyException, KeyOrderException, WxOrderCountException {
        // 解析链接
        List<String> urllist = UrlUtils.parseUrlsFromText(keyInfo.getKey());
        String verifyAlipayKey = systemConfigService.getValueCache(SystemConfigKeyEnum.ALIPAY_KEY_VERIFY);
        if(verifyAlipayKey!=null&&verifyAlipayKey.trim().equalsIgnoreCase("1")||true) {
            try {
                // 需要验证支付宝口令
                if (urllist.size() < 1) {
                    throw new Exception("口令中不包含链接");
                }
                AlipayOrderUtil.AlipayOrderTradeInfo tradeInfo = AlipayOrderUtil.getTradeInfo(urllist.get(0));
                String orderStatus = "";
                switch (tradeInfo.getStatus()) {
                    case AlipayOrderUtil.AlipayOrderTradeInfo.STATUS_CANCELED:
                        orderStatus = "订单已取消";
                        break;
                    case AlipayOrderUtil.AlipayOrderTradeInfo.STATUS_PAY:
                        orderStatus = "订单已支付";
                        break;
                    case AlipayOrderUtil.AlipayOrderTradeInfo.STATUS_NOT_PAY:
                        orderStatus = "订单未支付";
                        break;
                }
                if (tradeInfo == null) {
                    throw new Exception("口令内容获取失败");
                }
                // 验证内容
                DYOrderDto dto = keyOrderService.verifyKey(tradeInfo.getGoodsTitle(), orderStatus, tradeInfo.getItemRealAmount());
            }catch(KeyVerifyException ee){
                throw  ee;
            }
            catch(Exception e){
                throw new KeyVerifyException(KeyVerifyException.CODE_COMMON, e.getMessage());
            }
        }
    }
    @Test
    public void test1()  {
        SubmitKeyInfo keyInfo=new SubmitKeyInfo();
        keyInfo.setKey("【支fu`寳】亲,复制 Q:/dYsUzQV77s5  p:/S ZH2412 2020/11/27打开支付宝就可以帮我🏮付款啦💪https://ur.alipay.com/_Ig4toHTlLHbBqiJqb3dpC");
        try {
            addKey(keyInfo, 1L);
        } catch (KeyVerifyException e) {
            e.printStackTrace();
        } catch (KeyOrderException e) {
            e.printStackTrace();
        } catch (WxOrderCountException e) {
            e.printStackTrace();
        }
    }
}
src/test/java/com/taoke/autopay/LogTest.java
New file
@@ -0,0 +1,150 @@
package com.taoke.autopay;
import com.taoke.autopay.dao.KeyOrderMapper;
import com.taoke.autopay.entity.KeyOrder;
import com.taoke.autopay.utils.Constant;
import com.taoke.autopay.utils.TimeUtil;
import net.sf.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.yeshi.utils.StringUtil;
import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.util.*;
/**
 * @author hxh
 * @title: LogTest
 * @description: TODO
 * @date 2024/7/19 12:15
 */
@SpringBootTest
public class LogTest {
    @Resource
    private KeyOrderMapper keyOrderMapper;
    @Test
    public void parseLog() throws FileNotFoundException {
        String[] days = new String[]{"2024-07-15","2024-07-16","2024-07-17","2024-07-18"};
        for(String day:days) {
            Scanner scanner = new Scanner(new FileInputStream("D:\\文件传输\\交易\\日志文件\\xcp\\pay.log.gz."+day));
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if (!line.contains("setOrderNo:")) {
                    continue;
                }
                String[] sts = line.split("setOrderNo:")[1].split("-");
                String id = sts[0].trim();
                String money = sts[sts.length - 1].replace("¥", "");
                System.out.println(id + ":" + money);
                KeyOrder order = keyOrderMapper.selectById(id);
                if(order!=null){
                    KeyOrder update=new KeyOrder();
                    update.setId(id);
                    update.setOrderMoney(new BigDecimal(money));
                    keyOrderMapper.updateByPrimaryKeySelective(update);
                }
            }
            scanner.close();
        }
    }
    @Test
    public void parseLogForChannel() throws FileNotFoundException {
        String[] days = new String[]{"2024-07-15","2024-07-16","2024-07-17","2024-07-18"};
        for(String day:days) {
            Set<String> bps=new HashSet<>();
            Set<String> cyx=new HashSet<>();
            Scanner scanner = new Scanner(new FileInputStream("D:\\文件传输\\交易\\日志文件\\xcp\\info.log.gz."+day));
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if (!line.contains("抖音订单查询")) {
                    continue;
                }
                line =  line.split("dyorderApiLogger -")[1];
                int startIndex = line.indexOf(":");
                String tag = line.substring(0,startIndex).trim();
                String id =  line.substring(startIndex + 1,line.indexOf("-")).trim();
                String data =  line.substring(line.indexOf("-")+1);
                if(tag.contains("(1)")){
                    cyx.add(id);
                }else if(tag.contains("(2)")){
                    bps.add(id);
                }
            }
            Set<String> totalOrderNos=new HashSet<>();
            totalOrderNos.addAll(bps);
            totalOrderNos.addAll(cyx);
            Map<String,String> orderChannelMap = new HashMap<>();
            // 交集里面的订单不属于任何一个渠道
            Set<String> intersection = new HashSet<>(bps);
            intersection.retainAll(cyx);
            for(String r:intersection){
                orderChannelMap.put(r,null);
            }
            // 差集属于bps
            Set<String> difference = new HashSet<>(cyx);
            difference.removeAll(bps);
            for(String r:difference){
                orderChannelMap.put(r,Constant.ORDER_CHANNEL_BPS);
            }
            // 当天订单与totalOrderNos的所有差集属于cyx
            Date minCreateTime =new Date(TimeUtil.convertToTimeTemp(day,"yyyy-MM-dd"));
            Date maxCreateTime =TimeUtil.getNextDay(1,new Date(TimeUtil.convertToTimeTemp(day,"yyyy-MM-dd")).getTime());
            KeyOrderMapper.DaoQuery query=new KeyOrderMapper.DaoQuery();
            query.minCreateTime =minCreateTime;
            query.maxCreateTime =maxCreateTime;
            query.start = 0;
            query.count =10000;
            query.state = KeyOrder.STATE_PAY;
            List<KeyOrder> orders =  keyOrderMapper.list(query);
            Set<String> dayOrderNos=new HashSet<>();
            for(KeyOrder o:orders){
                if(!StringUtil.isNullOrEmpty(o.getOrderNo())) {
                    dayOrderNos.add(o.getOrderNo());
                }
            }
            dayOrderNos.removeAll(totalOrderNos);
            for(String r:dayOrderNos){
                orderChannelMap.put(r,Constant.ORDER_CHANNEL_CYX);
            }
        for(Iterator<String> its= orderChannelMap.keySet().iterator();its.hasNext();){
            String orderNo = its.next();
            query=new KeyOrderMapper.DaoQuery();
            query.orderNo = orderNo;
            query.start=0;
            query.count =100;
            orders =  keyOrderMapper.list(query);
            for(KeyOrder order:orders){
                if(order.getState()== KeyOrder.STATE_PAY){
                  String channel =  orderChannelMap.get(orderNo);
                  if(channel!=null){
                      KeyOrder update=new KeyOrder();
                      update.setId(order.getId());
                      update.setOrderChannel(channel);
                      update.setUpdateTime(new Date());
                      keyOrderMapper.updateByPrimaryKeySelective(update);
                  }
                }
            }
        }
            scanner.close();
        }
    }
}
src/test/java/com/taoke/autopay/MapperTest.java
@@ -1,10 +1,8 @@
package com.taoke.autopay;
import com.taoke.autopay.entity.AdminUser;
import com.taoke.autopay.entity.KeyOrder;
import org.junit.jupiter.api.Test;
import org.yeshi.utils.generater.mybatis.ColumnParseUtil;
import org.yeshi.utils.generater.mybatis.MyBatisMapperUtil;
/**
 * @author hxh
@@ -16,15 +14,17 @@
    @Test
    public void test() {
//        MyBatisMapperUtil.createMapper(ClientInfo.class);
//        MyBatisMapperUtil.createMapper(ChannelAgent.class);
//        MyBatisMapperUtil.createMapper(KeyOrder.class);
//        MyBatisMapperUtil.createMapper(SystemConfig.class);
//        MyBatisMapperUtil.createMapper(WxUserInfo.class);
//        MyBatisMapperUtil.createMapper(WxUserOrderCount.class);
//        MyBatisMapperUtil.createMapper(AdminUser.class);
        ColumnParseUtil.parseColumn(KeyOrder.class,
                "D:\\项目\\淘客代付系统\\taoke_autopay_server\\src\\main\\resources\\mapper\\KeyOrderMapper.xml");
//      System.out.println(  new BigDecimal("3.26").multiply(new BigDecimal(100)).setScale(0, RoundingMode.FLOOR).intValue());
src/test/java/com/taoke/autopay/WxUserTests.java
@@ -1,10 +1,12 @@
package com.taoke.autopay;
import com.taoke.autopay.service.WxUserService;
import com.taoke.autopay.utils.Constant;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.math.BigDecimal;
/**
 * @author hxh