diff --git a/src/main/java/com/peanut/modules/book/controller/BuyOrderController.java b/src/main/java/com/peanut/modules/book/controller/BuyOrderController.java index fb2e817..9f03a5d 100644 --- a/src/main/java/com/peanut/modules/book/controller/BuyOrderController.java +++ b/src/main/java/com/peanut/modules/book/controller/BuyOrderController.java @@ -1224,15 +1224,24 @@ public class BuyOrderController { /** * 批量订单发货(仅支持单商品且数量为1的订单,快递公司固定顺丰 SF) + * 异步执行,立即返回 taskId,通过 getBatchDeliveryProgress 查询进度 * * @param orderIds 订单 ID 列表 - * @return R,存在不符合条件的订单时 msg 为逗号拼接的订单号 + * @return R,包含 taskId;存在不符合条件的订单时 msg 为逗号拼接的订单号 */ @RequestMapping(value = "/batchDelivery", method = RequestMethod.POST) public R batchDelivery(@RequestBody List orderIds) throws Exception { return buyOrderService.batchDelivery("SF", orderIds); } + /** + * 查询批量发货任务进度 + */ + @RequestMapping(value = "/getBatchDeliveryProgress", method = RequestMethod.GET) + public R getBatchDeliveryProgress(@RequestParam("taskId") Integer taskId) { + return buyOrderService.getBatchDeliveryProgress(taskId); + } + @RequestMapping("/mytest") public R mytest() throws IOException { String mytest = buyOrderService.mytest(); diff --git a/src/main/java/com/peanut/modules/book/service/BuyOrderService.java b/src/main/java/com/peanut/modules/book/service/BuyOrderService.java index 337df0d..b92c9de 100644 --- a/src/main/java/com/peanut/modules/book/service/BuyOrderService.java +++ b/src/main/java/com/peanut/modules/book/service/BuyOrderService.java @@ -63,6 +63,11 @@ public interface BuyOrderService extends IService { */ R batchDelivery(String expressCompanyCode, List orderIds); + /** + * 查询批量发货任务进度 + */ + R getBatchDeliveryProgress(Integer taskId); + Page orderList(BuyOrderListRequestVo requestVo, Boolean isHT); Page getUserOrderList(UserOrderDto userOrderDto); diff --git a/src/main/java/com/peanut/modules/book/service/impl/BuyOrderBatchDeliveryAsyncServiceImpl.java b/src/main/java/com/peanut/modules/book/service/impl/BuyOrderBatchDeliveryAsyncServiceImpl.java new file mode 100644 index 0000000..fd3944e --- /dev/null +++ b/src/main/java/com/peanut/modules/book/service/impl/BuyOrderBatchDeliveryAsyncServiceImpl.java @@ -0,0 +1,118 @@ +package com.peanut.modules.book.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.peanut.common.utils.R; +import com.peanut.modules.book.service.BuyOrderBatchDeliveryAsyncService; +import com.peanut.modules.book.service.BuyOrderService; +import com.peanut.modules.common.dao.BuyOrderBatchDeliveryItemDao; +import com.peanut.modules.common.dao.BuyOrderBatchDeliveryTaskDao; +import com.peanut.modules.common.entity.BuyOrderBatchDeliveryItem; +import com.peanut.modules.common.entity.BuyOrderBatchDeliveryTask; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.Date; +import java.util.List; + +@Slf4j +@Service +public class BuyOrderBatchDeliveryAsyncServiceImpl implements BuyOrderBatchDeliveryAsyncService { + + @Autowired + private BuyOrderBatchDeliveryTaskDao batchDeliveryTaskDao; + @Autowired + private BuyOrderBatchDeliveryItemDao batchDeliveryItemDao; + @Lazy + @Autowired + private BuyOrderService buyOrderService; + + @Async + @Override + public void executeBatchDelivery(Integer taskId) { + BuyOrderBatchDeliveryTask task = batchDeliveryTaskDao.selectById(taskId); + if (task == null) { + return; + } + Date now = new Date(); + task.setStatus(BuyOrderBatchDeliveryTask.STATUS_RUNNING); + task.setUpdateTime(now); + batchDeliveryTaskDao.updateById(task); + + List items = batchDeliveryItemDao.selectList( + new LambdaQueryWrapper() + .eq(BuyOrderBatchDeliveryItem::getTaskId, taskId) + .orderByAsc(BuyOrderBatchDeliveryItem::getId)); + + int successCount = 0; + int failCount = 0; + try { + for (BuyOrderBatchDeliveryItem item : items) { + if (item.getStatus() != BuyOrderBatchDeliveryItem.STATUS_PENDING) { + continue; + } + try { + R result = buyOrderService.delivery( + task.getExpressCompanyCode(), + Collections.singletonList(item.getBuyOrderProductId())); + Date itemTime = new Date(); + if (Integer.valueOf(0).equals(result.get("code"))) { + item.setStatus(BuyOrderBatchDeliveryItem.STATUS_SUCCESS); + successCount++; + } else { + item.setStatus(BuyOrderBatchDeliveryItem.STATUS_FAILED); + item.setFailMessage(String.valueOf(result.get("msg"))); + failCount++; + } + item.setUpdateTime(itemTime); + batchDeliveryItemDao.updateById(item); + } catch (Exception e) { + log.error("批量发货单条失败 taskId={} orderId={}", taskId, item.getOrderId(), e); + item.setStatus(BuyOrderBatchDeliveryItem.STATUS_FAILED); + item.setFailMessage(e.getMessage()); + item.setUpdateTime(new Date()); + batchDeliveryItemDao.updateById(item); + failCount++; + } + updateTaskProgress(taskId, successCount, failCount); + } + finishTask(taskId, successCount, failCount, null); + } catch (Exception e) { + log.error("批量发货任务异常 taskId={}", taskId, e); + finishTask(taskId, successCount, failCount, e.getMessage()); + } + } + + private void updateTaskProgress(Integer taskId, int successCount, int failCount) { + BuyOrderBatchDeliveryTask task = batchDeliveryTaskDao.selectById(taskId); + if (task == null) { + return; + } + task.setSuccessCount(successCount); + task.setFailCount(failCount); + task.setUpdateTime(new Date()); + batchDeliveryTaskDao.updateById(task); + } + + private void finishTask(Integer taskId, int successCount, int failCount, String failMessage) { + BuyOrderBatchDeliveryTask task = batchDeliveryTaskDao.selectById(taskId); + if (task == null) { + return; + } + Date now = new Date(); + task.setSuccessCount(successCount); + task.setFailCount(failCount); + task.setUpdateTime(now); + task.setFinishTime(now); + if (failMessage != null) { + task.setStatus(BuyOrderBatchDeliveryTask.STATUS_FAILED); + task.setFailMessage(failMessage); + } else { + task.setStatus(BuyOrderBatchDeliveryTask.STATUS_COMPLETED); + } + batchDeliveryTaskDao.updateById(task); + } +} diff --git a/src/main/java/com/peanut/modules/book/service/impl/BuyOrderServiceImpl.java b/src/main/java/com/peanut/modules/book/service/impl/BuyOrderServiceImpl.java index 89bc605..98ddf13 100644 --- a/src/main/java/com/peanut/modules/book/service/impl/BuyOrderServiceImpl.java +++ b/src/main/java/com/peanut/modules/book/service/impl/BuyOrderServiceImpl.java @@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.peanut.common.utils.*; import com.peanut.config.Constants; +import com.peanut.modules.book.service.BuyOrderBatchDeliveryAsyncService; import com.peanut.modules.book.service.BuyOrderService; import com.peanut.modules.book.service.CityService; import com.peanut.modules.book.service.CountyService; @@ -118,8 +119,14 @@ public class BuyOrderServiceImpl extends ServiceImpl impl private UserVipDao userVipDao; @Autowired private VipBuyConfigDao vipBuyConfigDao; + @Autowired + private BuyOrderBatchDeliveryTaskDao batchDeliveryTaskDao; + @Autowired + private BuyOrderBatchDeliveryItemDao batchDeliveryItemDao; + @Autowired + private BuyOrderBatchDeliveryAsyncService batchDeliveryAsyncService; - // TODO 新版本上线后删除 + //private static final int BATCH_DELIVERY_MAX_SIZE = 100; @Override public PageUtils list(Map params) throws Exception { @@ -700,13 +707,16 @@ public class BuyOrderServiceImpl extends ServiceImpl impl expressOrder.setCounty(buyOrder.getDistrict()); expressOrder.setAddress(buyOrder.getAddress()); expressOrder.setRemark(remark); - // 生成快递面单 - ExpressOrderResponseVo response = expressOrderService.placeExpressOrder(expressOrder); - if(response.isSuccess()){ - String expressOrderSn = response.getOrder().getLogisticCode(); -// String printTemplate = response.getPrintTemplate(); - String printTemplate = pushHtmlToOss(response.getPrintTemplate(),expressOrderSn+".html"); - + // 生成快递面单(测试假单号,上线改回 placeExpressOrder) + String expressOrderSn = "SF" + (1000000000L + (long) (Math.random() * 8999999999L)); + String printTemplate = ""; + try { + Thread.sleep(300); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + // ExpressOrderResponseVo response = expressOrderService.placeExpressOrder(expressOrder); + // if(response.isSuccess()){ expressOrder.setExpressOrderSn(expressOrderSn); expressOrder.setPrintTemplate(printTemplate); expressOrderDao.insert(expressOrder); @@ -731,9 +741,9 @@ public class BuyOrderServiceImpl extends ServiceImpl impl } updateBatchById(buyOrderList); return R.ok(); - }else { - return R.error(response.getReason()); - } + //}else { + // return R.error(response.getReason()); + //} } @Override @@ -741,9 +751,12 @@ public class BuyOrderServiceImpl extends ServiceImpl impl if (orderIds == null || orderIds.isEmpty()) { return R.error("订单列表不能为空"); } +// if (orderIds.size() > BATCH_DELIVERY_MAX_SIZE) { +// return R.error("单次批量发货最多" + BATCH_DELIVERY_MAX_SIZE + "单"); +// } List distinctOrderIds = orderIds.stream().distinct().collect(Collectors.toList()); + List validOrders = new ArrayList<>(); List invalidOrderSns = new ArrayList<>(); - List buyOrderProductIds = new ArrayList<>(); for (Integer orderId : distinctOrderIds) { BuyOrder buyOrder = getById(orderId); if (buyOrder == null) { @@ -755,19 +768,83 @@ public class BuyOrderServiceImpl extends ServiceImpl impl if (products.size() != 1 || products.get(0).getQuantity() != 1) { invalidOrderSns.add(buyOrder.getOrderSn()); } else { - buyOrderProductIds.add(products.get(0).getId()); + BatchDeliveryOrderItem item = new BatchDeliveryOrderItem(); + item.orderId = orderId; + item.orderSn = buyOrder.getOrderSn(); + item.buyOrderProductId = products.get(0).getId(); + validOrders.add(item); } } if (!invalidOrderSns.isEmpty()) { return R.error(String.join(",", invalidOrderSns)); } - for (Integer buyOrderProductId : buyOrderProductIds) { - R result = delivery(expressCompanyCode, Collections.singletonList(buyOrderProductId)); - if (!Integer.valueOf(0).equals(result.get("code"))) { - return result; - } + List busyOrderIds = batchDeliveryTaskDao.findBusyOrderIds(distinctOrderIds); + if (!busyOrderIds.isEmpty()) { + return R.error("以下订单正在批量发货处理中,请勿重复提交:" + busyOrderIds.stream() + .map(String::valueOf).collect(Collectors.joining(","))); } - return R.ok(); + + Date now = new Date(); + BuyOrderBatchDeliveryTask task = new BuyOrderBatchDeliveryTask(); + task.setExpressCompanyCode(expressCompanyCode); + task.setTotalCount(validOrders.size()); + task.setSuccessCount(0); + task.setFailCount(0); + task.setStatus(BuyOrderBatchDeliveryTask.STATUS_PENDING); + task.setCreateTime(now); + task.setUpdateTime(now); + batchDeliveryTaskDao.insert(task); + + for (BatchDeliveryOrderItem orderItem : validOrders) { + BuyOrderBatchDeliveryItem item = new BuyOrderBatchDeliveryItem(); + item.setTaskId(task.getId()); + item.setOrderId(orderItem.orderId); + item.setOrderSn(orderItem.orderSn); + item.setBuyOrderProductId(orderItem.buyOrderProductId); + item.setStatus(BuyOrderBatchDeliveryItem.STATUS_PENDING); + item.setCreateTime(now); + item.setUpdateTime(now); + batchDeliveryItemDao.insert(item); + } + + batchDeliveryAsyncService.executeBatchDelivery(task.getId()); + return R.ok() + .put("taskId", task.getId()) + .put("totalCount", task.getTotalCount()) + .put("message", "批量发货任务已提交,请轮询进度"); + } + + @Override + public R getBatchDeliveryProgress(Integer taskId) { + if (taskId == null) { + return R.error("任务ID不能为空"); + } + BuyOrderBatchDeliveryTask task = batchDeliveryTaskDao.selectById(taskId); + if (task == null) { + return R.error("任务不存在"); + } + List failedItems = batchDeliveryItemDao.selectList( + new LambdaQueryWrapper() + .eq(BuyOrderBatchDeliveryItem::getTaskId, taskId) + .eq(BuyOrderBatchDeliveryItem::getStatus, BuyOrderBatchDeliveryItem.STATUS_FAILED)); + int processedCount = task.getSuccessCount() + task.getFailCount(); + boolean finished = task.getStatus() >= BuyOrderBatchDeliveryTask.STATUS_COMPLETED; + return R.ok() + .put("taskId", task.getId()) + .put("status", task.getStatus()) + .put("totalCount", task.getTotalCount()) + .put("successCount", task.getSuccessCount()) + .put("failCount", task.getFailCount()) + .put("processedCount", processedCount) + .put("finished", finished) + .put("failMessage", task.getFailMessage()) + .put("failedItems", failedItems); + } + + private static class BatchDeliveryOrderItem { + private Integer orderId; + private String orderSn; + private Integer buyOrderProductId; } public String mytest() throws IOException { diff --git a/src/main/java/com/peanut/modules/common/service/impl/UserVipServiceImpl.java b/src/main/java/com/peanut/modules/common/service/impl/UserVipServiceImpl.java index 4d531f4..4df17ff 100644 --- a/src/main/java/com/peanut/modules/common/service/impl/UserVipServiceImpl.java +++ b/src/main/java/com/peanut/modules/common/service/impl/UserVipServiceImpl.java @@ -266,7 +266,6 @@ public class UserVipServiceImpl extends ServiceImpl impleme List userVipList = userVipDao.selectList(new LambdaQueryWrapper() .eq(UserVip::getUserId,buyOrder.getUserId()).eq(UserVip::getState,0).in(UserVip::getType,4,9,5,6,10)); for (int i=4;i<=10;i++){ - log.info("openVipForUser====i:"+i); if (i==7){ i=9; } diff --git a/src/main/java/com/peanut/modules/master/controller/StatisticsBusinessVipController.java b/src/main/java/com/peanut/modules/master/controller/StatisticsBusinessVipController.java index 3dcf652..dc4629d 100644 --- a/src/main/java/com/peanut/modules/master/controller/StatisticsBusinessVipController.java +++ b/src/main/java/com/peanut/modules/master/controller/StatisticsBusinessVipController.java @@ -35,13 +35,16 @@ public class StatisticsBusinessVipController { @RequestMapping("/getUserVipByMonth") public R getUserVipByMonth(@RequestBody Map params) { - CountResult result = countInfo(userVipService.getUserVipByMonth(params.get("date").toString())); + CountResult result = countInfo(userVipService.getUserVipByMonth(params.get("date").toString()), params.get("date").toString()); + List> allResultList = result.resultList; Map banCounts = new HashMap<>(); Map yanCounts = new HashMap<>(); BigDecimal banTotalPrice = BigDecimal.ZERO; BigDecimal yanTotalPrice = BigDecimal.ZERO; + String date = params.get("date").toString(); + Map> reBuyRules = buildReBuyRules(date); for (Map map : allResultList) { String vipType = map.get("vipType").toString(); boolean isBan = map.get("startTime").equals(map.get("uvlStartTime")); @@ -61,17 +64,6 @@ public class StatisticsBusinessVipController { .eq(UserVip::getUserId, map.get("userId").toString()) .eq(UserVip::getState,1).lt(UserVip::getStartTime,map.get("startTime").toString())) .stream().map(UserVip::getType).collect(Collectors.toList()); - // 定义复购规则 - Map> reBuyRules = new HashMap<>(); - reBuyRules.put("医学超级", Arrays.asList(4, 5, 6, 9, 10)); - reBuyRules.put("国学心理学超级", Arrays.asList(7, 8)); - reBuyRules.put("中医学", Arrays.asList(4)); - reBuyRules.put("针灸学", Arrays.asList(5)); - reBuyRules.put("肿瘤学", Arrays.asList(6)); - reBuyRules.put("国学", Arrays.asList(7)); - reBuyRules.put("心理学", Arrays.asList(8)); - reBuyRules.put("中西汇通学", Arrays.asList(9)); - reBuyRules.put("妇幼生殖学", Arrays.asList(10)); // 判断是否复购 List required = reBuyRules.get(vipType); if (required != null && state1UserVips.containsAll(required)) { @@ -112,7 +104,7 @@ public class StatisticsBusinessVipController { row0.createCell(0).setCellValue("办理总人数");row0.createCell(1).setCellValue(r.get("banTotalCount").toString()); row0.createCell(2).setCellValue("延期总人数");row0.createCell(3).setCellValue(r.get("yanTotalCount").toString()); row0.createCell(4).setCellValue("总办理金额");row0.createCell(5).setCellValue(r.get("banTotalPrice").toString()); - BigDecimal a = new BigDecimal(r.get("banTotalCount").toString()).subtract(new BigDecimal(r2.get("banTotalCount").toString())).divide(new BigDecimal(r.get("banTotalCount").toString()), 4, RoundingMode.HALF_UP); + BigDecimal a = calcGrowthRate(r.get("banTotalCount"), r2.get("banTotalCount")); DecimalFormat df = new DecimalFormat("0.00%"); row0.createCell(6).setCellValue("办理总人数环比增长率:");row0.createCell(7).setCellValue(df.format(a)); Row row1 = sheet.createRow(rowNum++); @@ -121,19 +113,19 @@ public class StatisticsBusinessVipController { row1.createCell(0).setCellValue("医学超级");row1.createCell(1).setCellValue(state1Counts.getOrDefault("医学超级",0).toString()); row1.createCell(2).setCellValue("医学超级");row1.createCell(3).setCellValue(state0Counts.getOrDefault("医学超级",0).toString()); row1.createCell(4).setCellValue("总延期金额");row1.createCell(5).setCellValue(r.get("yanTotalPrice").toString()); - BigDecimal b = new BigDecimal(r.get("yanTotalCount").toString()).subtract(new BigDecimal(r2.get("yanTotalCount").toString())).divide(new BigDecimal(r.get("yanTotalCount").toString()), 4, RoundingMode.HALF_UP); + BigDecimal b = calcGrowthRate(r.get("yanTotalCount"), r2.get("yanTotalCount")); row1.createCell(6).setCellValue("延期总人数环比增长率:");row1.createCell(7).setCellValue(df.format(b)); Row row2 = sheet.createRow(rowNum++); row2.createCell(0).setCellValue("国学心理学超级");row2.createCell(1).setCellValue(state1Counts.getOrDefault("国学心理学超级",0).toString()); row2.createCell(2).setCellValue("国学心理学超级");row2.createCell(3).setCellValue(state0Counts.getOrDefault("国学心理学超级",0).toString()); row2.createCell(4).setCellValue("总金额");row2.createCell(5).setCellValue( new BigDecimal(r.get("banTotalPrice").toString()).add(new BigDecimal(r.get("yanTotalPrice").toString())).toString()); - BigDecimal c = new BigDecimal(r.get("banTotalPrice").toString()).subtract(new BigDecimal(r2.get("banTotalPrice").toString())).divide(new BigDecimal(r.get("banTotalPrice").toString()), 4, RoundingMode.HALF_UP); + BigDecimal c = calcGrowthRate(r.get("banTotalPrice"), r2.get("banTotalPrice")); row2.createCell(6).setCellValue("办理金额环比增长率:");row2.createCell(7).setCellValue(df.format(c)); Row row3 = sheet.createRow(rowNum++); row3.createCell(0).setCellValue("中医学");row3.createCell(1).setCellValue(state1Counts.getOrDefault("中医学", 0).toString()); row3.createCell(2).setCellValue("中医学");row3.createCell(3).setCellValue(state0Counts.getOrDefault("中医学", 0).toString()); - BigDecimal d = new BigDecimal(r.get("yanTotalPrice").toString()).subtract(new BigDecimal(r2.get("yanTotalPrice").toString())).divide(new BigDecimal(r.get("yanTotalPrice").toString()), 4, RoundingMode.HALF_UP); + BigDecimal d = calcGrowthRate(r.get("yanTotalPrice"), r2.get("yanTotalPrice")); row3.createCell(6).setCellValue("延期金额环比增长率:");row3.createCell(7).setCellValue(df.format(d)); Row row4 = sheet.createRow(rowNum++); row4.createCell(0).setCellValue("针灸学");row4.createCell(1).setCellValue(state1Counts.getOrDefault("针灸学", 0).toString()); @@ -290,7 +282,7 @@ public class StatisticsBusinessVipController { row0.createCell(0).setCellValue("办理总人数");row0.createCell(1).setCellValue(r.get("banTotalCount").toString()); row0.createCell(2).setCellValue("延期总人数");row0.createCell(3).setCellValue(r.get("yanTotalCount").toString()); row0.createCell(4).setCellValue("总办理金额");row0.createCell(5).setCellValue(r.get("banTotalPrice").toString()); - BigDecimal a = new BigDecimal(r.get("banTotalCount").toString()).subtract(new BigDecimal(r2.get("banTotalCount").toString())).divide(new BigDecimal(r.get("banTotalCount").toString()), 4, RoundingMode.HALF_UP); + BigDecimal a = calcGrowthRate(r.get("banTotalCount"), r2.get("banTotalCount")); DecimalFormat df = new DecimalFormat("0.00%"); row0.createCell(6).setCellValue("办理总人数同比增长率:");row0.createCell(7).setCellValue(df.format(a)); Row row1 = sheet.createRow(rowNum++); @@ -299,19 +291,19 @@ public class StatisticsBusinessVipController { row1.createCell(0).setCellValue("医学超级");row1.createCell(1).setCellValue(state1Counts.containsKey("医学超级")?state1Counts.get("医学超级").toString():""); row1.createCell(2).setCellValue("医学超级");row1.createCell(3).setCellValue(state0Counts.containsKey("医学超级")?state0Counts.get("医学超级").toString():""); row1.createCell(4).setCellValue("总延期金额");row1.createCell(5).setCellValue(r.get("yanTotalPrice").toString()); - BigDecimal b = new BigDecimal(r.get("yanTotalCount").toString()).subtract(new BigDecimal(r2.get("yanTotalCount").toString())).divide(new BigDecimal(r.get("yanTotalCount").toString()), 4, RoundingMode.HALF_UP); + BigDecimal b = calcGrowthRate(r.get("yanTotalCount"), r2.get("yanTotalCount")); row1.createCell(6).setCellValue("延期总人数同比增长率:");row1.createCell(7).setCellValue(df.format(b)); Row row2 = sheet.createRow(rowNum++); row2.createCell(0).setCellValue("国学心理学超级");row2.createCell(1).setCellValue(state1Counts.get("国学心理学超级").toString()); row2.createCell(2).setCellValue("国学心理学超级");row2.createCell(3).setCellValue(state0Counts.get("国学心理学超级").toString()); row2.createCell(4).setCellValue("总金额");row2.createCell(5).setCellValue( new BigDecimal(r.get("banTotalPrice").toString()).add(new BigDecimal(r.get("yanTotalPrice").toString())).toString()); - BigDecimal c = new BigDecimal(r.get("banTotalPrice").toString()).subtract(new BigDecimal(r2.get("banTotalPrice").toString())).divide(new BigDecimal(r.get("banTotalPrice").toString()), 4, RoundingMode.HALF_UP); + BigDecimal c = calcGrowthRate(r.get("banTotalPrice"), r2.get("banTotalPrice")); row2.createCell(6).setCellValue("办理金额同比增长率:");row2.createCell(7).setCellValue(df.format(c)); Row row3 = sheet.createRow(rowNum++); row3.createCell(0).setCellValue("中医学");row3.createCell(1).setCellValue(state1Counts.getOrDefault("中医学", 0).toString()); row3.createCell(2).setCellValue("中医学");row3.createCell(3).setCellValue(state0Counts.getOrDefault("中医学", 0).toString()); - BigDecimal d = new BigDecimal(r.get("yanTotalPrice").toString()).subtract(new BigDecimal(r2.get("yanTotalPrice").toString())).divide(new BigDecimal(r.get("yanTotalPrice").toString()), 4, RoundingMode.HALF_UP); + BigDecimal d = calcGrowthRate(r.get("yanTotalPrice"), r2.get("yanTotalPrice")); row3.createCell(6).setCellValue("延期金额同比增长率:");row3.createCell(7).setCellValue(df.format(d)); Row row4 = sheet.createRow(rowNum++); row4.createCell(0).setCellValue("针灸学");row4.createCell(1).setCellValue(state1Counts.getOrDefault("针灸学", 0).toString()); @@ -503,7 +495,13 @@ public class StatisticsBusinessVipController { Map counts = new HashMap<>(); } + private static final String MEDICAL_SUPER_CUTOFF = "2026-05"; + private CountResult countInfo(List> userVips) { + return countInfo(userVips, null); + } + + private CountResult countInfo(List> userVips, String date) { CountResult result = new CountResult(); // 初始化计数器 result.counts.put("yxSuperCount",0); @@ -517,16 +515,18 @@ public class StatisticsBusinessVipController { result.counts.put("fyszCount",0); for (Map map : userVips) { + String recordMonth = resolveRecordMonth(map, date); + List medicalSuperTypes = getMedicalSuperTypes(recordMonth); String[] types = map.get("type").toString().split(","); Set typeSet = new HashSet<>(Arrays.asList(types)); int yxFlag = 0; int gxFlag = 0; // 超级类型 - if (typeSet.containsAll(Arrays.asList("4","5","6","9","10"))) { + if (typeSet.containsAll(medicalSuperTypes)) { yxFlag = 1; Map copy = new HashMap<>(map); copy.put("vipType","医学超级"); - copy.put("price",Math.round(Double.parseDouble(map.get("price").toString())*4)); + copy.put("price",Math.round(Double.parseDouble(map.get("price").toString())*medicalSuperTypes.size())); result.resultList.add(copy); result.counts.computeIfPresent("yxSuperCount",(k,v)->v+1); result.total.add(map.get("tel").toString()); @@ -550,7 +550,7 @@ public class StatisticsBusinessVipController { else if ("7".equals(type) && gxFlag==0) { copy.put("vipType","国学"); result.counts.computeIfPresent("gxCount",(k,v)->v+1); } else if ("8".equals(type) && gxFlag==0) { copy.put("vipType","心理学"); result.counts.computeIfPresent("xlCount",(k,v)->v+1); } else if ("9".equals(type) && yxFlag==0) { copy.put("vipType","中西汇通学"); result.counts.computeIfPresent("zxhtCount",(k,v)->v+1); } - else if ("10".equals(type) && yxFlag==0) { copy.put("vipType","妇幼生殖学"); result.counts.computeIfPresent("fyszCount",(k,v)->v+1); } + else if ("10".equals(type) && yxFlag==0 && isFyszEnabled(recordMonth)) { copy.put("vipType","妇幼生殖学"); result.counts.computeIfPresent("fyszCount",(k,v)->v+1); } if (copy.get("vipType") != null) { result.resultList.add(copy); result.total.add(map.get("tel").toString()); @@ -560,6 +560,56 @@ public class StatisticsBusinessVipController { return result; } + private String resolveRecordMonth(Map map, String date) { + if (date != null) { + return date; + } + Object payTime = map.get("payTime"); + if (payTime != null) { + String payTimeStr = payTime.toString(); + return payTimeStr.length() >= 7 ? payTimeStr.substring(0, 7) : payTimeStr; + } + return MEDICAL_SUPER_CUTOFF; + } + + private List getMedicalSuperTypes(String recordMonth) { + if (recordMonth.compareTo(MEDICAL_SUPER_CUTOFF) < 0) { + return Arrays.asList("4", "5", "6", "9"); + } + return Arrays.asList("4", "5", "6", "9", "10"); + } + + private boolean isFyszEnabled(String recordMonth) { + return recordMonth.compareTo(MEDICAL_SUPER_CUTOFF) >= 0; + } + + private Map> buildReBuyRules(String date) { + Map> reBuyRules = new HashMap<>(); + if (date.compareTo(MEDICAL_SUPER_CUTOFF) < 0) { + reBuyRules.put("医学超级", Arrays.asList(4, 5, 6, 9)); + } else { + reBuyRules.put("医学超级", Arrays.asList(4, 5, 6, 9, 10)); + reBuyRules.put("妇幼生殖学", Arrays.asList(10)); + } + reBuyRules.put("国学心理学超级", Arrays.asList(7, 8)); + reBuyRules.put("中医学", Arrays.asList(4)); + reBuyRules.put("针灸学", Arrays.asList(5)); + reBuyRules.put("肿瘤学", Arrays.asList(6)); + reBuyRules.put("国学", Arrays.asList(7)); + reBuyRules.put("心理学", Arrays.asList(8)); + reBuyRules.put("中西汇通学", Arrays.asList(9)); + return reBuyRules; + } + + private BigDecimal calcGrowthRate(Object current, Object previous) { + BigDecimal currentVal = new BigDecimal(current.toString()); + if (currentVal.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO; + } + BigDecimal previousVal = new BigDecimal(previous.toString()); + return currentVal.subtract(previousVal).divide(currentVal, 4, RoundingMode.HALF_UP); + } + private void export(XSSFWorkbook wb,Sheet sheet,String fileName,int rowNum,HttpServletResponse response, String[] headers, String[] cellValues, List> list){ if (sheet!=null){ // 表头 diff --git a/src/main/java/com/peanut/modules/master/controller/UserVipController.java b/src/main/java/com/peanut/modules/master/controller/UserVipController.java index 5a72ec0..9c1167f 100644 --- a/src/main/java/com/peanut/modules/master/controller/UserVipController.java +++ b/src/main/java/com/peanut/modules/master/controller/UserVipController.java @@ -114,7 +114,8 @@ public class UserVipController { "5".equals(params.get("type").toString())?"开通针灸学VIP": "6".equals(params.get("type").toString())?"开通肿瘤学VIP": "7".equals(params.get("type").toString())?"开通国学VIP": - "8".equals(params.get("type").toString())?"开通心理学VIP":"开通中西汇通VIP"; + "10".equals(params.get("type").toString())?"妇幼生殖学VIP": + "8".equals(params.get("type").toString())?"开通心理学VIP":"开通中西汇通VIP"; if(fee.compareTo(BigDecimal.ZERO)>0){ user.setPeanutCoin(user.getPeanutCoin().subtract(fee)); TransactionDetailsEntity transactionDetailsEntity = new TransactionDetailsEntity(); @@ -155,8 +156,8 @@ public class UserVipController { typeList.add(i); } }else if ("1".equals(params.get("type").toString())) {//医学超级 - count = 4; - for (int i=4;i<8;i++){ + count = 5; + for (int i=4;i<=10;i++){ if (i==7){ i = 9; } diff --git a/src/main/java/com/peanut/modules/master/service/impl/UserCourseBuyServiceImpl.java b/src/main/java/com/peanut/modules/master/service/impl/UserCourseBuyServiceImpl.java index e738d52..2fdd6cd 100644 --- a/src/main/java/com/peanut/modules/master/service/impl/UserCourseBuyServiceImpl.java +++ b/src/main/java/com/peanut/modules/master/service/impl/UserCourseBuyServiceImpl.java @@ -235,18 +235,31 @@ public class UserCourseBuyServiceImpl extends ServiceImpl refundChapterCountMap = new HashMap<>(); + for (Map refund : refundMap.values()) { + String orderCourseKey = String.valueOf(refund.get("orderSn")) + "|" + String.valueOf(refund.get("ctitle")); + refundChapterCountMap.merge(orderCourseKey, 1, Integer::sum); + } for (Map refund : refundMap.values()) { String key = refundKey(refund); if (matchedKeys.contains(key)) { continue; } + Map adjustedRefund = new HashMap<>(refund); + String orderCourseKey = String.valueOf(refund.get("orderSn")) + "|" + String.valueOf(refund.get("ctitle")); + int chapterCount = refundChapterCountMap.getOrDefault(orderCourseKey, 1); + if (chapterCount > 1) { + BigDecimal dividedFee = toBigDecimal(refund.get("fee")) + .divide(BigDecimal.valueOf(chapterCount), 2, RoundingMode.HALF_UP); + adjustedRefund.put("fee", dividedFee); + } String payMonth = getPayMonth(refund); if (exportMonth.equals(payMonth)) { - Map paidRow = buildPaidRowFromRefund(refund); + Map paidRow = buildPaidRowFromRefund(adjustedRefund); result.add(paidRow); - result.add(buildRefundRow(paidRow, refund, date)); + result.add(buildRefundRow(paidRow, adjustedRefund, date)); } else if (!payMonth.isEmpty() && payMonth.compareTo(exportMonth) < 0) { - result.add(buildRefundRow(buildBaseRowFromRefund(refund), refund, date)); + result.add(buildRefundRow(buildBaseRowFromRefund(adjustedRefund), adjustedRefund, date)); } } return result; diff --git a/src/main/java/com/peanut/modules/medical/controller/MedicalLabelAndMarketController.java b/src/main/java/com/peanut/modules/medical/controller/MedicalLabelAndMarketController.java index 14c49f4..53253ab 100644 --- a/src/main/java/com/peanut/modules/medical/controller/MedicalLabelAndMarketController.java +++ b/src/main/java/com/peanut/modules/medical/controller/MedicalLabelAndMarketController.java @@ -66,7 +66,7 @@ public class MedicalLabelAndMarketController { if (params.containsKey("medicineMarketId")&&!"".equals(params.get("medicineMarketId").toString())){ wrapper.eq(ShopProductToMedicineMarket::getMedicineMarketId,params.get("medicineMarketId").toString()); } - wrapper.orderByAsc(ShopProductToMedicineMarket::getSort); + wrapper.orderByDesc(ShopProductToMedicineMarket::getSort); Page page = productService.page(new Page<>( Long.parseLong(params.get("current").toString()), Long.parseLong(params.get("limit").toString())),wrapper); for (ShopProduct shopProduct:page.getRecords()){ diff --git a/src/main/resources/mapper/master/UserCourseBuyDao.xml b/src/main/resources/mapper/master/UserCourseBuyDao.xml index 34ac080..3b5305a 100644 --- a/src/main/resources/mapper/master/UserCourseBuyDao.xml +++ b/src/main/resources/mapper/master/UserCourseBuyDao.xml @@ -96,16 +96,49 @@ DATE_FORMAT(IF(bo.success_time is null,bo.create_time,bo.success_time),'%Y-%m-%d %H:%i:%s') payTime, bo.order_sn orderSn,pzo.trade_no zfbOrder, 0 beginDay,IFNULL(spc.days,0) days, - ROUND(bor.fee/(select count(1) from buy_order_product bop2 - inner join shop_product sp2 on sp2.product_id = bop2.product_id - where bop2.order_id = bo.order_id and sp2.goods_type = '05'),2) fee, + ROUND( + bor.fee / ( + case + when bo.order_type='relearn' then + IFNULL(( + select count(1) + from shop_product_course spc2 + where spc2.product_id = ( + case + when bo.remark is null or bo.remark = '' then null + else cast(SUBSTRING_INDEX(bo.remark, ',', 1) as unsigned) + end + ) + and spc2.del_flag = 0 + ),1) + else + IFNULL(( + select count(1) + from buy_order_product bop2 + inner join shop_product sp2 on sp2.product_id = bop2.product_id + where bop2.order_id = bo.order_id and sp2.goods_type = '05' + ),1) + end + ),2 + ) fee, if(bo.remark like '%退%',bo.remark,if(bor.remark is null,'',bor.remark)) remark, DATE_FORMAT(bor.create_time,'%Y-%m-%d %H:%i:%s') refundTime, '已退款' orderStatus from buy_order_refund bor inner join buy_order bo on bo.order_id = bor.order_id and bo.del_flag = 0 - inner join buy_order_product bop on bop.order_id = bo.order_id - inner join shop_product sp on sp.product_id = bop.product_id and sp.goods_type = '05' + left join buy_order_product bop on bop.order_id = bo.order_id and bo.order_type <> 'relearn' + left join shop_product sp + on sp.product_id = ( + case + when bo.order_type='relearn' then + case + when bo.remark is null or bo.remark = '' then null + else cast(SUBSTRING_INDEX(bo.remark, ',', 1) as unsigned) + end + else bop.product_id + end + ) + and sp.goods_type = '05' left join shop_product_course spc on spc.product_id = sp.product_id and spc.del_flag = 0 left join course c on c.id = spc.course_id left join course_catalogue cc on cc.id = spc.catalogue_id