admin
2022-09-30 ffc56f912da5d6d842142ae4ea1856bc56f8bcb9
结算日志添加
18个文件已修改
2个文件已添加
515 ■■■■ 已修改文件
app/src/main/java/com/yeshi/makemoney/app/Application.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/controller/admin/goldcorn/GoldCornSettleRecordAdminController.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/dao/goldcorn/GoldCornConsumeRecordDao.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/entity/SystemEnum.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/exception/money/ExtractException.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/job/ExtractJob.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/service/impl/goldcorn/GoldCornMakeServiceImpl.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/service/impl/goldcorn/GoldCornSettleServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/service/impl/money/ExtractServiceImpl.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/service/inter/money/ExtractService.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/service/query/money/ExtractQuery.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/utils/LogUtil.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/utils/mq/CMQManager.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/resources/logback.xml 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/resources/static/admin/pages/goldcorn/gold_corn_settle_record_list.html 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/resources/static/admin/pages/money/extract_list.html 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/test/java/test/ExtractTest.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/test/java/test/Test.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/test/java/test/goldcorn/GoldCornTest.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/yeshi/makemoney/app/Application.java
@@ -1,5 +1,6 @@
package com.yeshi.makemoney.app;
import com.google.gson.Gson;
import com.ks.lib.common.exception.ParamsException;
import com.yeshi.makemoney.app.dto.mq.ExtractTransferResultMQMsg;
import com.yeshi.makemoney.app.dto.mq.GoldCornSettleMQMsg;
@@ -10,6 +11,7 @@
import com.yeshi.makemoney.app.service.inter.goldcorn.GoldCornSettleService;
import com.yeshi.makemoney.app.service.inter.money.ExtractService;
import com.yeshi.makemoney.app.utils.Constant;
import com.yeshi.makemoney.app.utils.LogUtil;
import com.yeshi.makemoney.app.utils.mq.CMQManager;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
@@ -40,6 +42,7 @@
@EnableTransactionManagement
//@EnableDubbo(scanBasePackages = "com.ks.push.service.remote")
public class Application implements ApplicationListener<ContextRefreshedEvent> {
    Logger settleLogger= LoggerFactory.getLogger("settleLog");
    private final static Logger logger = LoggerFactory.getLogger(Application.class);
    public static void main(String[] args) {
@@ -54,6 +57,8 @@
        logger.info("容器加载完毕");
        initMQMsgConsumer();
        initCOS();
        LogUtil.settleLogger.info("test123");
    }
    @Resource
@@ -70,24 +75,32 @@
            new JobThreadExecutorServiceImpl().run(new Runnable() {
                @Override
                public void run() {
                    Map<String, GoldCornSettleMQMsg> map = CMQManager.getInstance().consumeGoldCornSettleMsg(10);
                    if (map != null) {
                        for (Iterator<String> its = map.keySet().iterator(); its.hasNext(); ) {
                            String key = its.next();
                            GoldCornSettleMQMsg msg = map.get(key);
                            try {
                                settleLogger.info("消费结算消息开始:{}",new Gson().toJson(msg));
                                goldCornSettleService.settle(msg.getUid(), msg.getDay(),msg.getSettleId());
                                CMQManager.getInstance().deleteGoldCornSettleMsg(key);
                                settleLogger.info("消费结算消息成功:{}",new Gson().toJson(msg));
                            } catch (UserInfoException e) {
                                e.printStackTrace();
                                settleLogger.error("消费结算消息异常:{} ",new Gson().toJson(msg),e);
                            } catch (GoldCornMoneyExchangeRateRecordException e) {
                                e.printStackTrace();
                                settleLogger.error("消费结算消息异常:{} ",new Gson().toJson(msg),e);
                            } catch (UserMoneyRecordException e) {
                                e.printStackTrace();
                                settleLogger.error("消费结算消息异常:{} ",new Gson().toJson(msg),e);
                            } catch (GoldCornConsumeRecordException e) {
                                e.printStackTrace();
                                settleLogger.error("消费结算消息异常:{} ",new Gson().toJson(msg),e);
                            } catch (Exception e) {
                                e.printStackTrace();
                                settleLogger.error("消费结算消息异常:{} ",new Gson().toJson(msg),e);
                            }
                        }
                    }
app/src/main/java/com/yeshi/makemoney/app/controller/admin/goldcorn/GoldCornSettleRecordAdminController.java
@@ -2,12 +2,15 @@
import com.google.gson.*;
import com.ks.lib.common.exception.ParamsException;
import com.yeshi.makemoney.app.dto.mq.GoldCornSettleMQMsg;
import com.yeshi.makemoney.app.entity.goldcorn.GoldCornConsumeType;
import com.yeshi.makemoney.app.exception.goldcorn.GoldCornSettleRecordException;
import com.yeshi.makemoney.app.service.inter.goldcorn.GoldCornConsumeRecordService;
import com.yeshi.makemoney.app.service.inter.goldcorn.GoldCornGetRecordService;
import com.yeshi.makemoney.app.service.inter.goldcorn.GoldCornSettleService;
import com.yeshi.makemoney.app.service.query.goldcorn.GoldCornConsumeRecordQuery;
import com.yeshi.makemoney.app.utils.goldcorn.GoldCornUtil;
import com.yeshi.makemoney.app.utils.mq.CMQManager;
import com.yeshi.makemoney.app.vo.AcceptAdminData;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
@@ -42,6 +45,9 @@
    @Resource
    private GoldCornConsumeRecordService goldCornConsumeRecordService;
    @Resource
    private GoldCornGetRecordService goldCornGetRecordService;
    private Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new JsonSerializer<Date>() {
@@ -138,4 +144,31 @@
    }
    @ResponseBody
    @RequestMapping("retry")
    public String retry(String id, AcceptAdminData acceptAdminData) {
        if (id == null) {
            return JsonUtil.loadFalseResult("ID不能为空");
        }
        GoldCornSettleRecord record = goldCornSettleRecordService.get(id);
        if (record == null) {
            return JsonUtil.loadFalseResult("记录不存在");
        }
        long count = goldCornGetRecordService.countUidsByDay(record.getDay());
        int pageSize = 1000;
        int page = (int) (count % pageSize == 0 ? count / pageSize : count / pageSize + 1);
        for (int i = 0; i < page; i++) {
            List<Long> list = goldCornGetRecordService.getUidsByDay(record.getDay(), i + 1, pageSize);
            for (Long uid : list) {
                //加入到CMQ
                CMQManager.getInstance().addGoldCornSettleMsg(new GoldCornSettleMQMsg(record.getId(), uid, record.getDay(), System.currentTimeMillis()));
            }
        }
        return JsonUtil.loadTrueResult(gson.toJson(record));
    }
}
app/src/main/java/com/yeshi/makemoney/app/dao/goldcorn/GoldCornConsumeRecordDao.java
@@ -34,6 +34,9 @@
        if (bean.getUid() != null) {
            update.set("uid", bean.getUid());
        }
        if (bean.getEventId() != null) {
            update.set("eventId", bean.getEventId());
        }
        if (bean.getCornNum() != null) {
            update.set("cornNum", bean.getCornNum());
        }
app/src/main/java/com/yeshi/makemoney/app/entity/SystemEnum.java
@@ -7,7 +7,7 @@
 * @date 2021/11/15 11:17
 */
public enum SystemEnum {
    svmm("椰视赚钱短视频", "com.yeshi.makemoney.video", "");
    svmm("椰视极速版", "com.yeshi.makemoney.video", "");
    private String name;
    private String packageName;
    private String bundleId;
app/src/main/java/com/yeshi/makemoney/app/exception/money/ExtractException.java
@@ -18,6 +18,9 @@
    public final static int CODE_ALREADY_DONE = 401;
    public final static int CODE_WX_PAY_ACCOUNT_NO_MONEY = 801;
    public ExtractException(int code, String msg) {
        super(code, msg);
    }
app/src/main/java/com/yeshi/makemoney/app/job/ExtractJob.java
New file
@@ -0,0 +1,69 @@
package com.yeshi.makemoney.app.job;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yeshi.makemoney.app.entity.SystemEnum;
import com.yeshi.makemoney.app.entity.money.Extract;
import com.yeshi.makemoney.app.exception.money.ExtractException;
import com.yeshi.makemoney.app.service.inter.goldcorn.GoldCornGetRecordService;
import com.yeshi.makemoney.app.service.inter.money.ExtractService;
import com.yeshi.makemoney.app.service.manager.PushManager;
import com.yeshi.makemoney.app.utils.goldcorn.GoldCornUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.yeshi.utils.StringUtil;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
 * @author hxh
 * @title: PushJob
 * @description: 提现任务
 * @date 2022/5/7 17:44
 */
@Component
public class ExtractJob {
    private Logger logger = LoggerFactory.getLogger(ExtractJob.class);
    @Resource
    private ExtractService extractService;
    /**
     * @return com.xxl.job.core.biz.model.ReturnT<java.lang.String>
     * @author hxh
     * @description 通过提现
     * @date 14:30 2022/6/20
     * @param: param
     **/
    @XxlJob("pass-extract")
    public ReturnT<String> passExtract(String param) throws Exception {
        if (StringUtil.isNullOrEmpty(param)) {
            param = "1";
        }
        Date minDate = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24L * 2);
        long count = extractService.countNeedPassRecord(new BigDecimal(param), minDate);
        int pageSize = 100;
        int pageCount = (int) (count % 100 == 0 ? count / 100 : count / 100 + 1);
        for (int p = 0; p < pageCount; p++) {
            List<Extract> extractList = extractService.listNeedPassRecord(new BigDecimal(param), minDate, p + 1, pageSize);
            for (Extract extract : extractList) {
                try {
                    extractService.passExtract(extract.getId(), "auto_verify_extract");
                } catch (ExtractException e) {
                    e.printStackTrace();
                    logger.error("机器通过提现出错:id-{}", extract.getId(), e);
                }
            }
        }
        return ReturnT.SUCCESS;
    }
}
app/src/main/java/com/yeshi/makemoney/app/service/impl/goldcorn/GoldCornMakeServiceImpl.java
@@ -23,6 +23,8 @@
import com.yeshi.makemoney.app.utils.factory.UserMoneyRecordFactory;
import com.yeshi.makemoney.app.utils.factory.goldcorn.GoldCornConsumeRecordFactory;
import com.yeshi.makemoney.app.utils.goldcorn.GoldCornUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -45,6 +47,7 @@
 */
@Service
public class GoldCornMakeServiceImpl implements GoldCornMakeService {
    Logger taskLogger = LoggerFactory.getLogger("taskLog");
    @Resource
    private GoldCornGetFrequencyConfigService goldCornGetFrequencyConfigService;
@@ -92,44 +95,53 @@
        query.setUid(user.getId());
        query.setType(type);
        //间隔判断
        if (config.getMinSpaceTime() != null) {
            List<GoldCornGetRecord> list = goldCornGetRecordService.list(query, 1, 1);
            if (list != null && list.size() > 0 && time.getTime() - list.get(0).getCreateTime().getTime() < config.getMinSpaceTime() * 1000L) {
                String msg = String.format("需要间隔%s秒以上", config.getMinSpaceTime());
                throw new GoldCornMakeException(GoldCornMakeException.CODE_GET_FREQUENCY_TIME_LIMIT, msg);
        try {
            //间隔判断
            if (config.getMinSpaceTime() != null) {
                List<GoldCornGetRecord> list = goldCornGetRecordService.list(query, 1, 1);
                if (list != null && list.size() > 0 && time.getTime() - list.get(0).getCreateTime().getTime() < config.getMinSpaceTime() * 1000L) {
                    String msg = String.format("需要间隔%s秒以上", config.getMinSpaceTime());
                    throw new GoldCornMakeException(GoldCornMakeException.CODE_GET_FREQUENCY_TIME_LIMIT, msg);
                }
            }
            Date startTime = null;
            Date endTime = time;
            if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.minute) {
                startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyyMMdd HHmm"), "yyyyMMdd HHmm"));
            } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.hour) {
                startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyyMMdd HH"), "yyyyMMdd HH"));
            } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.day) {
                startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyyMMdd"), "yyyyMMdd"));
            } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.week) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(endTime.getTime());
                int subDay = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 2 + 7) % 7;
                startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime() - 1000 * 60 * 60 * 24L * subDay, "yyyyMMdd"), "yyyyMMdd"));
            } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.month) {
                startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyyMM"), "yyyyMM"));
            } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.year) {
                startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyy"), "yyyy"));
            }
            query.setFormat("yyyyMMdd HH:mm:ss");
            query.setStartTime(TimeUtil.getGernalTime(startTime.getTime(), query.getFormat()));
            //service里面有减去1天
            query.setEndTime(TimeUtil.getGernalTime(endTime.getTime() - 1000 * 60 * 60 * 24L, query.getFormat()));
            Map<GoldCornGetType, Long> countMap = goldCornGetRecordService.sumEventCount(query);
            if (countMap.get(type) != null && (countMap.get(type) >= config.getLimitCount())) {
                String msg = String.format("超出%s次/%s的限制", config.getLimitCount(), config.getTimeUnit().getName());
                throw new GoldCornMakeException(GoldCornMakeException.CODE_GET_FREQUENCY_COUNT_LIMIT, msg);
            }
            return config.getLimitCount() - (countMap.get(type) != null ? countMap.get(type) : 0);
        } catch (GoldCornMakeException e) {
            //频率限制
            taskLogger.error("#频率受限# uid:{} type:{} time:{}  msg:{}", user.getId(), type.name(), TimeUtil.getGernalTime(time.getTime(), "yyyy-MM-dd HH:mm:ss SSS"), e.getMsg());
            throw e;
        }
        Date startTime = null;
        Date endTime = time;
        if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.minute) {
            startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyyMMdd HHmm"), "yyyyMMdd HHmm"));
        } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.hour) {
            startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyyMMdd HH"), "yyyyMMdd HH"));
        } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.day) {
            startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyyMMdd"), "yyyyMMdd"));
        } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.week) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(endTime.getTime());
            int subDay = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 2 + 7) % 7;
            startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime() - 1000 * 60 * 60 * 24L * subDay, "yyyyMMdd"), "yyyyMMdd"));
        } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.month) {
            startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyyMM"), "yyyyMM"));
        } else if (config.getTimeUnit() == GoldCornGetFrequencyConfig.GoldCornGetFrequencyTimeUnit.year) {
            startTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(endTime.getTime(), "yyyy"), "yyyy"));
        }
        query.setFormat("yyyyMMdd HH:mm:ss");
        query.setStartTime(TimeUtil.getGernalTime(startTime.getTime(), query.getFormat()));
        //service里面有减去1天
        query.setEndTime(TimeUtil.getGernalTime(endTime.getTime() - 1000 * 60 * 60 * 24L, query.getFormat()));
        Map<GoldCornGetType, Long> countMap = goldCornGetRecordService.sumEventCount(query);
        if (countMap.get(type) != null && (countMap.get(type) >= config.getLimitCount())) {
            String msg = String.format("超出%s次/%s的限制", config.getLimitCount(), config.getTimeUnit().getName());
            throw new GoldCornMakeException(GoldCornMakeException.CODE_GET_FREQUENCY_COUNT_LIMIT, msg);
        }
        return config.getLimitCount() - (countMap.get(type) != null ? countMap.get(type) : 0);
    }
@@ -241,7 +253,7 @@
                continue;
            }
            //获取兑换记录的主键ID,不需要多余的数据
            GoldCornConsumeRecord record = GoldCornConsumeRecordFactory.createExchange(uid, GoldCornUtil.getFormatDay(date), 0, new BigDecimal(0.1),null);
            GoldCornConsumeRecord record = GoldCornConsumeRecordFactory.createExchange(uid, GoldCornUtil.getFormatDay(date), 0, new BigDecimal(0.1), null);
            //查询资金记录是否有该记录
            try {
                UserMoneyRecord userMoneyRecord = UserMoneyRecordFactory.createGoldCornExchange(record);
@@ -359,6 +371,17 @@
    @Transactional(rollbackFor = Exception.class)
    @Override
    public GoldCornMakeResultDTO scanNews(Long uid, boolean isDouble, Date time, int num) throws GoldCornGetPriceException, UserInfoException, GoldCornMakeException, GoldCornGetFrequencyConfigException {
        //防刷机制
        if (num < 0) {
            num = 0;
        }
        //1个很大的数
        if (num > 20) {
            num = 1;
        }
        UserInfo user = userInfoService.get(uid);
        if (user == null) {
            throw new UserInfoException(UserInfoException.CODE_NOT_EXIST, "用户不存在");
app/src/main/java/com/yeshi/makemoney/app/service/impl/goldcorn/GoldCornSettleServiceImpl.java
@@ -1,5 +1,6 @@
package com.yeshi.makemoney.app.service.impl.goldcorn;
import com.google.gson.Gson;
import com.ks.lib.common.exception.ParamsException;
import com.ks.push.exception.BPushTaskException;
import com.yeshi.makemoney.app.dto.mq.GoldCornSettleMQMsg;
@@ -25,6 +26,8 @@
import com.yeshi.makemoney.app.utils.factory.msg.UserMsgFactory;
import com.yeshi.makemoney.app.utils.goldcorn.GoldCornUtil;
import com.yeshi.makemoney.app.utils.mq.CMQManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yeshi.utils.ThreadUtil;
@@ -44,6 +47,7 @@
 */
@Service
public class GoldCornSettleServiceImpl implements GoldCornSettleService {
    Logger settleLogger= LoggerFactory.getLogger("settleLog");
    @Resource
    private GoldCornGetRecordService goldCornGetRecordService;
@@ -110,7 +114,9 @@
            List<Long> list = goldCornGetRecordService.getUidsByDay(day, i + 1, pageSize);
            for (Long uid : list) {
                //加入到CMQ
                CMQManager.getInstance().addGoldCornSettleMsg(new GoldCornSettleMQMsg(record.getId(), uid, day, System.currentTimeMillis()));
                GoldCornSettleMQMsg msg=  new GoldCornSettleMQMsg(record.getId(), uid, day, System.currentTimeMillis());
                settleLogger.info("加入结算队列:{}",new Gson().toJson(msg));
                CMQManager.getInstance().addGoldCornSettleMsg(msg);
            }
        }
@@ -123,6 +129,11 @@
        long cornNum = goldCornGetRecordService.getGoldCornByDay(uid, GoldCornUtil.convertFormatDay(day));
        //金币数量
        GoldCornConsumeRecord record = GoldCornConsumeRecordFactory.createExchange(uid, day, (int) cornNum, rate, settleId);
        if(goldCornConsumeRecordService.get(record.getId())!=null){
            //已经结算过了
            return;
        }
        try {
            UserMoneyRecord moneyRecord = UserMoneyRecordFactory.createGoldCornExchange(record);
            userMoneyService.addUserMoney(moneyRecord);
app/src/main/java/com/yeshi/makemoney/app/service/impl/money/ExtractServiceImpl.java
@@ -117,6 +117,27 @@
        return new Gson().fromJson(value, ExtractConfig.class);
    }
    @Override
    public List<Extract> listNeedPassRecord(BigDecimal maxMoney, Date minCreateTime, int page, int pageSize) {
        DaoQuery daoQuery = new DaoQuery();
        daoQuery.state = Extract.STATE_NOT_PROCESS;
        daoQuery.minCreateTime = minCreateTime;
        daoQuery.maxMoney = maxMoney;
        daoQuery.sortList = Arrays.asList(new String[]{"create_time asc"});
        daoQuery.start = (page - 1) * pageSize;
        daoQuery.count = pageSize;
        return extractMapper.list(daoQuery);
    }
    @Override
    public long countNeedPassRecord(BigDecimal maxMoney, Date minCreateTime) {
        DaoQuery daoQuery = new DaoQuery();
        daoQuery.state = Extract.STATE_NOT_PROCESS;
        daoQuery.minCreateTime = minCreateTime;
        daoQuery.maxMoney = maxMoney;
        return extractMapper.count(daoQuery);
    }
    private void validateExtract(BigDecimal money, UserInfo user) throws ExtractException {
        ExtractConfig config = getExtractConfig(user.getSystem());
        if (config == null) {
@@ -261,10 +282,21 @@
        if (extract.getType() == ExtractPayType.alipay) {
            transferByAlipay(extract, adminId);
        } else {
            transferByWX(extract, adminId, systemConfigService.getValueCache(user.getSystem(), SystemConfigKey.wxAppId));
          String result =  transferByWX(extract, adminId, systemConfigService.getValueCache(user.getSystem(), SystemConfigKey.wxAppId));
            Map<String, String> resultMap = WXUtil.parseXML(result);
            if ("SUCCESS".equalsIgnoreCase(resultMap.get("return_code")) && "SUCCESS".equalsIgnoreCase(resultMap.get("result_code"))) {
                ;
            } else {
                String errCode = resultMap.get("err_code");
                String errMsg = resultMap.get("err_code_des");
                boolean noMoney = "NOTENOUGH".equalsIgnoreCase(errCode);
                if(noMoney) {
                    throw new ExtractException(ExtractException.CODE_WX_PAY_ACCOUNT_NO_MONEY,"微信支付账户余额不足");
                }
            }
        }
    }
    @Transactional(rollbackFor = Exception.class)
@@ -372,18 +404,20 @@
        }
    }
    private void transferByWX(Extract extract, String adminId, String wxAPPId) {
    private String transferByWX(Extract extract, String adminId, String wxAPPId) {
        //获取用户的系统
        UserInfo user = userInfoService.get(extract.getUser().getId());
        String appName = user.getSystem().getName();
        //理由
        String result = WXPayUtil.payToOpenId(wxAPPId, extract.getAccount(), Constant.wxTransferConfig.getMchId(), Constant.wxTransferConfig.getKey(), Constant.wxTransferConfig.getCertPwd(), this.getClass().getClassLoader().getResourceAsStream(Constant.wxTransferConfig.getCertPath()), "makemoney" + extract.getId(), extract.getMoney(), "提现", extract.getIp());
        String result = WXPayUtil.payToOpenId(wxAPPId, extract.getAccount(), Constant.wxTransferConfig.getMchId(), Constant.wxTransferConfig.getKey(), Constant.wxTransferConfig.getCertPwd(), this.getClass().getClassLoader().getResourceAsStream(Constant.wxTransferConfig.getCertPath()), "makemoney" + extract.getId(), extract.getMoney(), String.format("来自%s的提现",appName), extract.getIp());
        try {
            CMQManager.getInstance().addExtractResultMsg(new ExtractTransferResultMQMsg(extract.getId(), result, adminId));
            logger.info("提现:添加处理队列成功-" + extract.getId());
        } catch (Exception e) {
            logger.error("提现:微信提现CMQ异常:{}", result + ",提现信息" + GsonUtil.toJson(extract));
        }
        return result;
    }
@@ -434,7 +468,7 @@
        if (noMoney) {
            Extract updateExtract = new Extract();
            updateExtract.setId(extract.getId());
            updateExtract.setState(Extract.STATE_PROCESSING);
            updateExtract.setState(Extract.STATE_NOT_PROCESS);
            updateExtract.setReason(msg);
            extractMapper.updateByPrimaryKeySelective(updateExtract);
        } else {
app/src/main/java/com/yeshi/makemoney/app/service/inter/money/ExtractService.java
@@ -125,4 +125,25 @@
    public ExtractConfig getExtractConfig(SystemEnum system);
    /**
     * @author hxh
     * @description 列举需要通过的记录
     * @date 14:24 2022/6/20
     * @param: maxMoney
     * @return java.util.List<com.yeshi.makemoney.app.entity.money.Extract>
     **/
    public List<Extract> listNeedPassRecord(BigDecimal maxMoney,Date minCreateTime,int page,int pageSize);
    /**
     * @author hxh
     * @description 需要通过的记录列表
     * @date 14:25 2022/6/20
     * @param: maxMoney
     * @return long
     **/
    public long countNeedPassRecord(BigDecimal maxMoney,Date minCreateTime);
}
app/src/main/java/com/yeshi/makemoney/app/service/query/money/ExtractQuery.java
@@ -4,10 +4,7 @@
public class ExtractQuery  extends BaseQuery {
    private Long uid;
    private Integer state;
    public Long getUid() {
        return uid;
app/src/main/java/com/yeshi/makemoney/app/utils/LogUtil.java
New file
@@ -0,0 +1,14 @@
package com.yeshi.makemoney.app.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @author hxh
 * @title: LogUtil
 * @description: 日志
 * @date 2022/9/9 10:22
 */
public class LogUtil {
    public static Logger settleLogger= LoggerFactory.getLogger("settleLog");
}
app/src/main/java/com/yeshi/makemoney/app/utils/mq/CMQManager.java
@@ -5,6 +5,8 @@
import com.yeshi.makemoney.app.dto.mq.AddGoldCornMQMsg;
import com.yeshi.makemoney.app.dto.mq.ExtractTransferResultMQMsg;
import com.yeshi.makemoney.app.dto.mq.GoldCornSettleMQMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yeshi.utils.StringUtil;
import org.yeshi.utils.mq.TDMQUtil;
@@ -19,6 +21,7 @@
 * @date 2022/4/1 17:06
 */
public class CMQManager {
    Logger logger= LoggerFactory.getLogger(CMQManager.class);
    private static String secretId = "AKIDTlpgJhLjOozvd6QI2XnpfGbgV4NQJk25";
    private static String secretKey = "xhCSUHo55oHUQ6XicFcmfIgspX0EEzWo";
    private static CMQManager cmqManager;
@@ -94,6 +97,7 @@
    public void addAddGoldCornMsg(AddGoldCornMQMsg msg) {
        String content = new Gson().toJson(msg);
        tdmqUtil.sendMsg(QUEUE_ADD_GOLDCORN, content);
    }
@@ -123,7 +127,10 @@
     **/
    public void addGoldCornSettleMsg(GoldCornSettleMQMsg msg) {
        String content = new Gson().toJson(msg);
        logger.debug("添加结算消息开始:",content);
        TDMQUtil.getInstance().sendMsg(QUEUE_GOLDCORN_SETTLE, content);
        //添加日志
        logger.debug("添加结算消息结束:{}",content);
    }
    public Map<String, GoldCornSettleMQMsg> consumeGoldCornSettleMsg(int count) {
app/src/main/resources/logback.xml
@@ -35,7 +35,63 @@
        <endpoint>ap-guangzhou.cls.tencentcs.com</endpoint>
        <accessKeyId>${tencent.log.accesskey}</accessKeyId>
        <accessKeySecret>${tencent.log.accessKeySecret}</accessKeySecret>
        <topicId>dsp</topicId>
        <topicId>7400eab9-e40c-40aa-a1d3-2084af09a76a</topicId>
        <!-- 可选项 详见 '参数说明'-->
        <totalSizeInBytes>104857600</totalSizeInBytes>
        <maxBlockMs>0</maxBlockMs>
        <sendThreadCount>8</sendThreadCount>
        <batchSizeThresholdInBytes>524288</batchSizeThresholdInBytes>
        <batchCountThreshold>4096</batchCountThreshold>
        <lingerMs>2000</lingerMs>
        <retries>10</retries>
        <baseRetryBackoffMs>100</baseRetryBackoffMs>
        <maxRetryBackoffMs>50000</maxRetryBackoffMs>
        <!-- 可选项 设置时间格式 -->
        <timeFormat>yyyy-MM-dd'T'HH:mm:ssZ</timeFormat>
        <timeZone>Asia/Shanghai</timeZone>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <mdcFields>THREAD_ID,MDC_KEY</mdcFields>
    </appender>
    <appender name="taskLogAppender" class="com.tencentcloudapi.cls.LoghubAppender">
        <!--必选项-->
        <endpoint>ap-guangzhou.cls.tencentcs.com</endpoint>
        <accessKeyId>${tencent.log.accesskey}</accessKeyId>
        <accessKeySecret>${tencent.log.accessKeySecret}</accessKeySecret>
        <topicId>dc22b452-1006-46c9-b86f-97baf823a1ee</topicId>
        <!-- 可选项 详见 '参数说明'-->
        <totalSizeInBytes>104857600</totalSizeInBytes>
        <maxBlockMs>0</maxBlockMs>
        <sendThreadCount>8</sendThreadCount>
        <batchSizeThresholdInBytes>524288</batchSizeThresholdInBytes>
        <batchCountThreshold>4096</batchCountThreshold>
        <lingerMs>2000</lingerMs>
        <retries>10</retries>
        <baseRetryBackoffMs>100</baseRetryBackoffMs>
        <maxRetryBackoffMs>50000</maxRetryBackoffMs>
        <!-- 可选项 设置时间格式 -->
        <timeFormat>yyyy-MM-dd'T'HH:mm:ssZ</timeFormat>
        <timeZone>Asia/Shanghai</timeZone>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <mdcFields>THREAD_ID,MDC_KEY</mdcFields>
    </appender>
    <appender name="settleLogAppender" class="com.tencentcloudapi.cls.LoghubAppender">
        <!--必选项-->
        <endpoint>ap-guangzhou.cls.tencentcs.com</endpoint>
        <accessKeyId>${tencent.log.accesskey}</accessKeyId>
        <accessKeySecret>${tencent.log.accessKeySecret}</accessKeySecret>
        <topicId>9c4583b7-ca4f-4907-af58-ebafe5e67cfe</topicId>
        <!-- 可选项 详见 '参数说明'-->
        <totalSizeInBytes>104857600</totalSizeInBytes>
@@ -137,6 +193,26 @@
        <appender-ref ref="tencentLogAppender"></appender-ref>
    </logger>
    <logger name="com.yeshi.makemoney.app.utils.mq.CMQManager" level="DEBUG" additivity="false">
        <appender-ref ref="tencentLogAppender"></appender-ref>
    </logger>
    <logger name="com.yeshi.makemoney.app.aop.SignValidate" level="ERROR" additivity="false">
        <appender-ref ref="tencentLogAppender"></appender-ref>
    </logger>
    <logger name="taskLog" level="INFO" additivity="false">
        <appender-ref ref="taskLogAppender"></appender-ref>
    </logger>
    <logger name="settleLog" level="INFO" additivity="false">
        <appender-ref ref="settleLogAppender"></appender-ref>
    </logger>
    <!-- 一切logger都会继承自root,root默认的层级level为debug -->
    <root level="INFO">
        <!--在控制台中输出所在层级对应level(以及大于level)的日志信息,因为这里并没有设置LevelFilter-->
app/src/main/resources/static/admin/pages/goldcorn/gold_corn_settle_record_list.html
@@ -76,6 +76,10 @@
        <a title="" href="javascript:;" lay-event="refresh">
            <i class="layui-icon">&#xe669;</i>
        </a>
        <a class="layui-btn layui-btn-sm" title="" href="javascript:;" lay-event="retry">
           重试
        </a>
    </div>
</script>
@@ -197,6 +201,8 @@
                                    app.refreshItem(data.id, function (res) {
                                        obj.update(res);
                                    });
                                }else if(obj.event === 'retry'){
                                    app.retry(data.id);
                                }
                            });
@@ -276,6 +282,16 @@
                        }
                    }, function (e) {
                    });
                },
                retry: function (id) {
                    ksapp.post("/admin/api/goldcorn/settle/retry", {id: id}, function (e) {
                        if (e.code == 0) {
                            layer.msg("更新成功");
                        } else {
                            layer.msg(e.msg);
                        }
                    }, function (e) {
                    });
                }
app/src/main/resources/static/admin/pages/money/extract_list.html
@@ -93,10 +93,6 @@
</script>
<script type="text/html" id="optContainer">
</script>
<script type="text/html" id="statusContainer">
    <div class="layui-btn-container">
        {{# if(d.status==0){ }}
@@ -123,6 +119,20 @@
    <img src="{{d.}}"/>
    <input type="checkbox" name="sex" value="{{d.id}}" lay-skin="switch" lay-text="女|男" lay-filter="sexDemo" {{ d.id==
           10003 ? 'checked': ''}} >
</script>
<script type="text/html" id="optContainer">
    <div class="layui-btn-container">
        <a class="layui-btn {{d.state==0?'':'layui-btn-disabled'}}" title="通过" onclick="app.passExtract({{d.state}},{{d.id}})"
           href="javascript:;">
           通过
        </a>
        <a class="layui-btn layui-btn-danger"  title="去处理" onclick="xadmin.open('处理提现记录', 'extract_process.html?id= {{d.id}}', null, null, true)"
           href="javascript:;">
            去处理
        </a>
    </div>
</script>
<script>
@@ -164,14 +174,16 @@
                            toolbar: "#toolbar",
                            totalRow: true,
                            cols: [[{type: 'checkbox', title: "ID"},
                                {field: 'id', width: 80, sort: false, title: "ID"},
                                {field: 'money', width: 80, sort: false, title: "提现金额"},
                                {
                                    field: 'user', width: 80, sort: false, title: "用户ID", templet: function (res) {
                                        return res.user.id;
                                    }
                                },
                                {field: 'money', width: 80, sort: false, title: "提现金额"},
                                {field: 'type', width: 80, sort: false, title: "付款渠道"},
                                {field: 'name', width: 80, sort: false, title: "姓名(支付宝)"},
                                {field: 'account', width: 120, sort: false, title: "账号/OpenId"},
@@ -193,6 +205,7 @@
                                {field: 'reason', width: 200, sort: false, title: "原因"},
                                {field: 'successTime', width: 150, sort: false, title: "通过时间"},
                                {field: 'createTime', width: 150, sort: false, title: "创建时间"},
                                {fixed: 'right', width: 150, title: "操作", toolbar: '#optContainer'}
                            ]],
                            page: true,
                            parseData: function (res) { //res 即为原始返回的数据
@@ -267,6 +280,28 @@
                            curr: 1 //重新从第 1 页开始
                        }
                    });
                },
                passExtract: function (state,id) {
                    if(state!=0){
                        return;
                    }
                    layer.confirm('是否通过提现申请?', {icon: 3, title: '提示'}, function (index) {
                        layer.close(index);
                        //确定
                        ksapp.post('/admin/api/money/extract/passExtract', {id: id}, function (res) {
                            if (res.code == 0) {
                                layer.msg("成功");
                            } else if (res.code == 50002) {
                                app.openVerifyDialog();
                            } else {
                                layer.msg(res.msg);
                            }
                        }, function (res) {
                        });
                    });
                },
                openVerifyDialog: function () {
                    xadmin.open('邮件验证', 'extract_email_code.html', 350, 160);
                }
            }
        });
app/src/test/java/test/ExtractTest.java
@@ -1,7 +1,12 @@
package test;
import com.yeshi.makemoney.app.Application;
import com.yeshi.makemoney.app.job.ExtractJob;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.yeshi.utils.wx.WXPayUtil;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -13,12 +18,21 @@
 * @description: TODO
 * @date 2022/4/1 10:51
 */
@SpringBootTest(classes = Application.class)
public class ExtractTest {
    @Resource
    private ExtractJob extractJob;
    public static void main(String[] args) throws FileNotFoundException {
        WXPayUtil.payToOpenId("wx428de66710fac55b", "odx5JwzVHBcEan-TtlGNKPzNuTlI", "1520950211", "XYJkJ2018FAfaodCCx899mLl138rfGVd", "1520950211", new FileInputStream(new File("D:\\项目\\返利券\\商户平台\\1520950211_20220401_cert\\apiclient_cert.p12")), "buwanwithdraw1", new BigDecimal(1.00), "提现", "192.168.3.122");
    }
    @Test
    public void autoVerify() throws Exception {
        //extractJob.passExtract("");
    }
}
app/src/test/java/test/Test.java
@@ -1,9 +1,15 @@
package test;
import com.qcloud.cmq.Account;
import com.qcloud.cmq.Queue;
import com.qcloud.cmq.entity.CmqResponse;
import org.yeshi.utils.FileUtil;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@@ -16,7 +22,11 @@
public class Test {
    public static void main(String[] args) throws IOException {
        String dir = "C:\\Users\\Administrator\\Desktop\\ocr";
//        if(1>0){
//            test1();
//            return;
//        }
        String dir = "C:\\Users\\Administrator\\Desktop\\ocr\\gpcode";
        File[] fs = new File(dir).listFiles();
        Set<String> md5Set = new HashSet<>();
        for (File f : fs) {
@@ -33,4 +43,9 @@
    }
    private static void test1() throws Exception{
    }
}
app/src/test/java/test/goldcorn/GoldCornTest.java
@@ -2,14 +2,17 @@
import com.ks.lib.common.exception.ParamsException;
import com.yeshi.makemoney.app.Application;
import com.yeshi.makemoney.app.dto.mq.GoldCornSettleMQMsg;
import com.yeshi.makemoney.app.entity.SystemEnum;
import com.yeshi.makemoney.app.entity.goldcorn.*;
import com.yeshi.makemoney.app.exception.goldcorn.*;
import com.yeshi.makemoney.app.exception.user.UserInfoException;
import com.yeshi.makemoney.app.service.inter.goldcorn.*;
import com.yeshi.makemoney.app.service.query.goldcorn.GoldCornConsumeRecordQuery;
import com.yeshi.makemoney.app.utils.mq.CMQManager;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.yeshi.utils.TimeUtil;
import javax.annotation.Resource;
import java.math.BigDecimal;
@@ -94,6 +97,24 @@
    @Test
    public void settle() {
//        goldCornSettleService.startSettle(new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 1L));
//        CMQManager.getInstance().addGoldCornSettleMsg(new GoldCornSettleMQMsg(record.getId(), uid, day, System.currentTimeMillis()));
        //重新结算
        GoldCornConsumeRecordQuery query = new GoldCornConsumeRecordQuery();
        query.setType(GoldCornConsumeType.changeMoney);
        query.setEventId("2022-06-22-svmm");
        query.setType(GoldCornConsumeType.changeMoney);
        List<GoldCornConsumeRecord> list=  goldCornConsumeRecordService.list(query,1,1000);
        int count=0;
        for(GoldCornConsumeRecord record:list){
           if(record.getCreateTime().getTime()> TimeUtil.convertToTimeTemp("2022-06-29","yyyy-MM-dd")){
               GoldCornConsumeRecord update=new GoldCornConsumeRecord();
               update.setId(record.getId());
               update.setEventId("2022-06-28-svmm");
               goldCornConsumeRecordService.update(update);
           }
        }
    }
pom.xml
@@ -158,7 +158,7 @@
        <dependency>
            <groupId>com.yeshi</groupId>
            <artifactId>utils</artifactId>
            <version>0.3.8</version>
            <version>0.3.9</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.data</groupId>