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