From d54bf5affbe623f36903ff267f436beb9f216d7c Mon Sep 17 00:00:00 2001 From: Van0313 <60689272+Van0313@users.noreply.github.com> Date: Fri, 16 May 2025 23:43:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=B7=E4=BF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/van/business/util/OrderUtil.java | 182 +++++++++--------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/src/main/java/cn/van/business/util/OrderUtil.java b/src/main/java/cn/van/business/util/OrderUtil.java index bb4c911..733df6d 100644 --- a/src/main/java/cn/van/business/util/OrderUtil.java +++ b/src/main/java/cn/van/business/util/OrderUtil.java @@ -5,18 +5,20 @@ import cn.van.business.model.jd.OrderRow; import cn.van.business.repository.OrderRowRepository; import lombok.AllArgsConstructor; import lombok.Getter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.loggerger; +import org.slf4j.loggergerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; +import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.ZoneId; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -31,6 +33,7 @@ import static cn.van.business.util.WXUtil.*; */ @Service public class OrderUtil { + private static final Logger logger = LoggerFactory.getLogger(OrderUtil.class); @Autowired private StringRedisTemplate redisTemplate; @@ -48,82 +51,90 @@ public class OrderUtil { */ @Async("threadPoolTaskExecutor") public void orderToWx(OrderRow orderRow, Boolean isAutoFlush) { - // 获取订单当前状态 - Integer newValidCode = orderRow.getValidCode(); - String oldValidCode = redisTemplate.opsForValue().get(ORDER_ROW_KEY + orderRow.getId()); - // 价保 - Double newProPriceAmount = orderRow.getProPriceAmount(); + try { + // 获取订单当前状态 + Integer newValidCode = orderRow.getValidCode(); + String oldValidCode = getFromRedis(ORDER_ROW_KEY + orderRow.getId()); + // 检查Redis中是否有旧的状态码,没有的话赋予默认值 + Integer lastValidCode = oldValidCode != null ? Integer.parseInt(oldValidCode) : -100; + // 先更新 Redis 状态,防止消息发送失败导致重复触发 + redisTemplate.opsForValue().set(ORDER_ROW_KEY + orderRow.getId(), String.valueOf(orderRow.getValidCode())); - // 检查Redis中是否有旧的状态码,没有的话赋予默认值 - Integer lastValidCode = oldValidCode != null ? Integer.parseInt(oldValidCode) : -100; + // 订单变化:当 isAutoFlush == false 或状态确实有变化时,进行消息发送 + if (!isAutoFlush || !lastValidCode.equals(newValidCode)) { + String content = getFormattedOrderInfo(orderRow); + String wxId = getWxidFromJdid(orderRow.getUnionId().toString()); - // 订单变化 - if (!isAutoFlush || !lastValidCode.equals(newValidCode)) { - // 当 isAutoFlush 为 false 或状态确实有变化时,进行消息发送 - String content = getFormattedOrderInfo(orderRow); - String wxId = getWxidFromJdid(orderRow.getUnionId().toString()); - if (Util.isNotEmpty(wxId)) { - wxUtil.sendTextMessage(wxId, content, 1, wxId, true); - // 加一个简短的今日订单统计 - int[] param = {-1}; - List superAdmins = getSuperAdmins(wxId); - List unionIds = new ArrayList<>(); - for (WXUtil.SuperAdmin superAdmin : superAdmins) { - String unionId = superAdmin.getUnionId(); - unionIds.add(Long.valueOf(unionId)); + if (Util.isNotEmpty(wxId)) { + wxUtil.sendTextMessage(wxId, content, 1, wxId, true); + + // 发送今日统计信息 + sendDailyStats(wxId); } - List orderRows = orderRowRepository.findByValidCodeNotInAndUnionIdIn(param, unionIds); - - List todayOrders = filterOrdersByDate(orderRows, 0); - // 分割统计每个京粉今天下单多少个订单,避免一天一个京粉下单太多 - HashMap> stringListHashMap = new HashMap<>(); - List cachedOrders = new ArrayList<>(); - for (OrderRow todayOrder : todayOrders) { - String unionId = todayOrder.getUnionId().toString(); - if (stringListHashMap.containsKey(unionId)) { - cachedOrders = stringListHashMap.get(unionId); - } else { - cachedOrders = new ArrayList<>(); - } - cachedOrders.add(todayOrder); - stringListHashMap.put(unionId, cachedOrders); - - } - // 只统计今天下单的京粉,因为有的京粉休息是不下单的 - StringBuilder resultContent = new StringBuilder(); - for (Map.Entry> entry : stringListHashMap.entrySet()) { - String unionId = entry.getKey(); - List orderRows2 = entry.getValue(); - OrderStats stats = calculateStats(orderRows2); - resultContent.append(buildStatsContent("京粉 : " + getRemarkFromJdid(unionId) , stats)); - } - - OrderStats orderStats = calculateStats(todayOrders); - wxUtil.sendTextMessage(wxId, buildStatsContent("今日总统计 : ", orderStats) + " \n 详 : \n ━━━━━━━━━━━━\n" + resultContent, 1, wxId, true); - } - } - // 更新 Redis 状态值 - redisTemplate.opsForValue().set(ORDER_ROW_KEY + orderRow.getId(), String.valueOf(orderRow.getValidCode())); - if (!newProPriceAmount.equals(0.0)){ - String oldProPriceAmount = redisTemplate.opsForValue().get(ORDER_ROW_JB_KEY + orderRow.getId()); - if (Util.isNotEmpty(oldProPriceAmount)) { - if (!oldProPriceAmount.equals(newProPriceAmount.toString())) { + // 处理价保逻辑 + BigDecimal newProPriceAmount = Optional.ofNullable(orderRow.getProPriceAmount()).map(BigDecimal::new).orElse(BigDecimal.ZERO); + + if (BigDecimal.ZERO.compareTo(newProPriceAmount) < 0) { + String oldProPriceAmountStr = getFromRedis(ORDER_ROW_JB_KEY + orderRow.getId()); + BigDecimal oldProPriceAmount = oldProPriceAmountStr == null ? BigDecimal.ZERO : new BigDecimal(oldProPriceAmountStr); + + if (newProPriceAmount.compareTo(oldProPriceAmount) != 0) { String wxId = getWxidFromJdid(orderRow.getUnionId().toString()); if (Util.isNotEmpty(wxId)) { String content = getFormattedOrderInfo(orderRow); - wxUtil.sendTextMessage(wxId, "[Broken] [Broken] [Broken] 价保提醒 [Broken] [Broken] [Broken] " + newProPriceAmount + "\n" + content, 1, wxId, true); + String alertMsg = "[Broken][Broken][Broken] 价保提醒 [Broken][Broken][Broken] " + newProPriceAmount + "\n" + content; + wxUtil.sendTextMessage(wxId, alertMsg, 1, wxId, true); } } - } - // 不管价保与否,都要写入redis - redisTemplate.opsForValue().set(ORDER_ROW_JB_KEY + orderRow.getId(), "0.0"); + // 不管是否变动都写入 Redis,用于下次比较 + redisTemplate.opsForValue().set(ORDER_ROW_JB_KEY + orderRow.getId(), newProPriceAmount.toString()); + } + + } catch (Exception e) { + logger.error("处理订单微信通知失败: {}", e.getMessage(), e); + // 可加入重试机制或上报监控 + } + } + + private void sendDailyStats(String wxId) { + List superAdmins = getSuperAdmins(wxId); + if (superAdmins.isEmpty()) return; + + List unionIds = superAdmins.stream().map(admin -> Long.valueOf(admin.getUnionId())).collect(Collectors.toList()); + + List orderRows = orderRowRepository.findByValidCodeNotInAndUnionIdIn(new int[]{-1}, unionIds); + List todayOrders = filterOrdersByDate(orderRows, 0); + + if (todayOrders.isEmpty()) return; + + // 按照 unionId 分组统计 + Map> grouped = todayOrders.stream().collect(Collectors.groupingBy(o -> o.getUnionId().toString())); + + StringBuilder resultContent = new StringBuilder(); + for (Map.Entry> entry : grouped.entrySet()) { + String unionId = entry.getKey(); + OrderStats stats = calculateStats(entry.getValue()); + resultContent.append(buildStatsContent("京粉 : " + getRemarkFromJdid(unionId), stats)); } + OrderStats totalStats = calculateStats(todayOrders); + String totalMsg = buildStatsContent("今日总统计 : ", totalStats) + " \n详:\n━━━━━━━━━━━━\n" + resultContent; + + wxUtil.sendTextMessage(wxId, totalMsg, 1, wxId, true); + } + + private String getFromRedis(String key) { + try { + return redisTemplate.opsForValue().get(key); + } catch (Exception e) { + logger.warn("Redis get 失败 key={}", key, e); + return null; + } } /** @@ -136,8 +147,7 @@ public class OrderUtil { String wxId = getWxidFromJdid(orderRowList.get(0).getUnionId().toString()); StringBuilder content = new StringBuilder(); content.append("批量订单:\n\r ").append(" 共 ").append(orderRowList.size()).append("单 \r"); - List filterList = orderRowList.stream().filter(orderRow -> orderRow.getValidCode() != 2 - && orderRow.getValidCode() != 3).toList(); + List filterList = orderRowList.stream().filter(orderRow -> orderRow.getValidCode() != 2 && orderRow.getValidCode() != 3).toList(); content.append("移除 拆单或者取消 的订单, 共 ").append(filterList.size()).append("单: \n\r"); for (OrderRow orderRow : filterList) { content.append("\r\n"); @@ -162,9 +172,7 @@ public class OrderUtil { ValidCodeConverter converter = new ValidCodeConverter(); Long unionId = orderRow.getUnionId(); String remarkFromJdid = getRemarkFromJdid(String.valueOf(unionId)); - StringBuilder orderInfo = new StringBuilder() - .append(" ").append(getEmjoy(orderRow.getValidCode())).append(" ") - .append(converter.getCodeDescription(orderRow.getValidCode())).append("\r"); + StringBuilder orderInfo = new StringBuilder().append(" ").append(getEmjoy(orderRow.getValidCode())).append(" ").append(converter.getCodeDescription(orderRow.getValidCode())).append("\r"); //if (oldValidCode != -100 && !oldValidCode.equals(orderRow.getValidCode())) { // orderInfo.insert(0, "从 :" + getEmjoy(oldValidCode) + " " @@ -175,21 +183,13 @@ public class OrderUtil { orderInfo //+ "订单+sku:" + orderRow.getId() + "\r" - .append("京粉:").append(remarkFromJdid).append("\r") - .append("订单:").append(orderRow.getOrderId()).append(" (") - .append(orderRow.getPlus() == 1 ? "plus" : "非plus").append(")\r") - .append("名称:").append(orderRow.getSkuName()).append("\r").append("\r") + .append("京粉:").append(remarkFromJdid).append("\r").append("订单:").append(orderRow.getOrderId()).append(" (").append(orderRow.getPlus() == 1 ? "plus" : "非plus").append(")\r").append("名称:").append(orderRow.getSkuName()).append("\r").append("\r") //+ "商品单价:" + orderRow.getPrice() + "\r" //+ "商品数量:" + orderRow.getSkuNum() + "\r" //+ "商品总价:" + (orderRow.getPrice() * orderRow.getSkuNum()) + "\r" .append("计佣金额:").append(orderRow.getEstimateCosPrice()).append("\r") //+ "金额:" + orderRow.getActualCosPrice() + "\r" - .append("比例:").append(orderRow.getCommissionRate()).append("\r") - .append("[Packet] 佣金:").append(orderRow.getEstimateFee()).append("\r") - .append("下单:").append(formatter.format(orderRow.getOrderTime())).append("\r") - .append("完成:").append(orderRow.getFinishTime() != null - ? formatter.format(orderRow.getFinishTime()) - : "未完成"); + .append("比例:").append(orderRow.getCommissionRate()).append("\r").append("[Packet] 佣金:").append(orderRow.getEstimateFee()).append("\r").append("下单:").append(formatter.format(orderRow.getOrderTime())).append("\r").append("完成:").append(orderRow.getFinishTime() != null ? formatter.format(orderRow.getFinishTime()) : "未完成"); return orderInfo.toString(); } @@ -235,12 +235,11 @@ public class OrderUtil { //} - return "订单:" + orderRow.getOrderId() + " (" + (orderRow.getPlus() == 1 ? "plus" : "非plus") + ")\r" - +"走的京粉:"+ remarkFromJdid + "\r" + return "订单:" + orderRow.getOrderId() + " (" + (orderRow.getPlus() == 1 ? "plus" : "非plus") + ")\r" + "走的京粉:" + remarkFromJdid + "\r" - +"状态:" + (converter.getCodeDescription(orderRow.getValidCode())) + "\r" + + "状态:" + (converter.getCodeDescription(orderRow.getValidCode())) + "\r" - + "标题:" + orderRow.getSkuName() + "\r\n"+ "\r\n" + + "标题:" + orderRow.getSkuName() + "\r\n" + "\r\n" //+ "商品单价:" + orderRow.getPrice() + "\r" //+ "商品数量:" + orderRow.getSkuNum() + "\r" //+ "商品总价:" + (orderRow.getPrice() * orderRow.getSkuNum()) + "\r" @@ -250,15 +249,14 @@ public class OrderUtil { //+ "比例:" + orderRow.getCommissionRate() + "\r" + "佣金:" + orderRow.getEstimateFee() + "\r\n" - + "下单:" + formatter.format(orderRow.getOrderTime()) + "\r" - + "完成:" + (orderRow.getFinishTime() != null ? formatter.format(orderRow.getFinishTime()) : "未完成") + "\r"; + + "下单:" + formatter.format(orderRow.getOrderTime()) + "\r" + "完成:" + (orderRow.getFinishTime() != null ? formatter.format(orderRow.getFinishTime()) : "未完成") + "\r"; } /** * JDUtil拷贝的方法,避免循环注入 - * */ + */ - private List filterOrdersByDate(List orderRows, int daysBack) { + private List filterOrdersByDate(List orderRows, int daysBack) { LocalDate now = LocalDate.now(); return orderRows.stream().filter(order -> { @@ -269,7 +267,8 @@ public class OrderUtil { return !orderDate.isBefore(now.minusDays(daysBack)) && !orderDate.isAfter(now); }).collect(Collectors.toList()); } - private OrderStats calculateStats(List orders) { + + private OrderStats calculateStats(List orders) { long paid = orders.stream().filter(o -> o.getValidCode() == 16).count(); long pending = orders.stream().filter(o -> o.getValidCode() == 15).count(); long canceled = orders.stream().filter(o -> o.getValidCode() != 16 && o.getValidCode() != 17).count(); @@ -277,6 +276,7 @@ public class OrderUtil { return new OrderStats(orders.size(), orders.size() - canceled, paid, orders.stream().filter(o -> o.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum(), pending, orders.stream().filter(o -> o.getValidCode() == 15).mapToDouble(OrderRow::getEstimateFee).sum(), canceled, completed, orders.stream().filter(o -> o.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum(), getStreamForWeiGui(orders).count(), getStreamForWeiGui(orders).mapToDouble(o -> o.getEstimateCosPrice() * o.getCommissionRate() * 0.01).sum()); } + private String buildStatsContent(String title, OrderStats stats) { StringBuilder content = new StringBuilder(); content//[爱心][Wow][Packet][Party][Broken][心碎][亲亲][色] @@ -289,6 +289,7 @@ public class OrderUtil { .append("[Packet] 待付款佣金:").append(String.format("%.2f", stats.getPendingCommission())).append("\n").append("━━━━━━━━━━━━\n"); return content.toString(); } + private Stream getStreamForWeiGui(List todayOrders) { return todayOrders.stream().filter(orderRow -> orderRow.getValidCode() == 13 || orderRow.getValidCode() == 25 || orderRow.getValidCode() == 26 || orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28 || orderRow.getValidCode() == 29); } @@ -296,8 +297,7 @@ public class OrderUtil { // 统计指标DTO @Getter @AllArgsConstructor - static - class OrderStats { + static class OrderStats { private long totalOrders; // 总订单数 private long validOrders; // 有效订单数(不含取消) private long paidOrders; // 已付款订单