From cbf28e8d7eb03d6671680fd87acc3831f422ed3f Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Wed, 14 Oct 2026 10:16:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AF=8F=E6=97=A5=E8=AE=A2=E9=A4=90=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../canteen/vo/app/DailyMenuAppVO.java | 2 +- .../CanteenDailyMenuController.java | 8 ++-- .../controller/CanteenSpuController.java | 9 ++++ .../service/CanteenDailyMenuService.java | 7 +++ .../canteen/service/CanteenSpuService.java | 8 ++++ .../impl/CanteenDailyMenuServiceImpl.java | 46 +++++++++++++++---- .../service/impl/CanteenSpuServiceImpl.java | 23 ++++++++++ .../mapper/CanteenDailyMenuMapper.xml | 9 ++-- .../hard/api/dto/order/HardOrderDto.java | 6 +++ .../mapper/order/HardOrderMapper.xml | 14 +++++- 10 files changed, 113 insertions(+), 19 deletions(-) diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/app/DailyMenuAppVO.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/app/DailyMenuAppVO.java index f900a2c0..1d4c701d 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/app/DailyMenuAppVO.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/app/DailyMenuAppVO.java @@ -116,7 +116,7 @@ public class DailyMenuAppVO { private Integer remainOfflineStock; /** - * 商品销量,仅用于详情页展示。 + * 当日移动端已订份数(取 online_sold),供 App 详情「已订」展示;不是 canteen_spu 历史累计销量。 */ private Integer salesCount; diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenDailyMenuController.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenDailyMenuController.java index a4047e07..aa2042dd 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenDailyMenuController.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenDailyMenuController.java @@ -300,17 +300,19 @@ public class CanteenDailyMenuController { * 按硬件订单净销量回填当日线上/线下 sold(配额不动)。 * 用于历史 sold 未累计、或怀疑销量漂移时的运维纠偏。 */ - @Operation(summary = "按订单重算当日分池销量", description = "覆盖 online_sold/offline_sold,不改配额") + @Operation(summary = "按订单重算分池销量", description = "覆盖 online_sold/offline_sold,不改配额;传 dailyMenuId 时只重算该行") @SysLog("按订单重算每日菜谱销量") @PutMapping("/syncChannelSold") @PreAuthorize("@pms.hasPermission('canteen_canteenDailyMenu_edit')") public R syncChannelSold(@RequestParam("merchantId") Long merchantId, - @RequestParam("mealDate") String mealDate) { + @RequestParam("mealDate") String mealDate, + @RequestParam(value = "dailyMenuId", required = false) Long dailyMenuId) { if (merchantId == null || StrUtil.isBlank(mealDate)) { return R.failed("商户和用餐日不能为空"); } try { - return canteenDailyMenuService.syncChannelSoldFromOrders(merchantId, LocalDate.parse(mealDate.trim())); + return canteenDailyMenuService.syncChannelSoldFromOrders(merchantId, LocalDate.parse(mealDate.trim()), + dailyMenuId); } catch (Exception ex) { return R.failed("用餐日格式应为 yyyy-MM-dd"); diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenSpuController.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenSpuController.java index 59ad4f3b..259a0cb4 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenSpuController.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenSpuController.java @@ -469,6 +469,15 @@ public class CanteenSpuController { return R.ok(canteenSpuService.loadComboItemVos(spuIds)); } + /** + * 反查「含该组成单品」的套餐及每份含本菜数量,供每日菜谱相关订单并入套餐单。 + */ + @GetMapping("/comboParentsByChild") + @PreAuthorize("@pms.hasPermission('canteen_canteenDailyMenu_view')") + public R> comboParentsByChild(@RequestParam("childSpuId") Long childSpuId) { + return R.ok(canteenSpuService.mapComboQtyByChildSpuId(childSpuId)); + } + /** * 为无用户令牌的 Hardware 异步打印任务提供套餐组成查询,复用管理端相同的数据装配逻辑。 * diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenDailyMenuService.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenDailyMenuService.java index 3ba8e168..d6b97a97 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenDailyMenuService.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenDailyMenuService.java @@ -116,4 +116,11 @@ public interface CanteenDailyMenuService extends IService syncChannelSoldFromOrders(Long merchantId, LocalDate mealDate); + + /** + * 同 {@link #syncChannelSoldFromOrders(Long, LocalDate)};{@code dailyMenuId} 非空时只重算该菜谱行。 + * + * @param dailyMenuId 每日菜谱行 ID,空则重算当日全部 + */ + R syncChannelSoldFromOrders(Long merchantId, LocalDate mealDate, Long dailyMenuId); } diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenSpuService.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenSpuService.java index 9b956ddc..4b977e80 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenSpuService.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenSpuService.java @@ -129,6 +129,14 @@ public interface CanteenSpuService extends IService { */ Map> loadComboItemVos(List comboSpuIds); + /** + * 查出「组成中含该单品」的套餐及其每份套餐含本菜份数,供相关订单并入套餐单并折算本菜份数。 + * + * @param childSpuId 组成单品 SPU ID + * @return key=套餐 SPU ID,value=每份套餐含本菜数量;无则空 Map + */ + Map mapComboQtyByChildSpuId(Long childSpuId); + /** * 按购物车商品 ID 批量加载打印凭证名称(套餐名优先、商品名兜底)。 * diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenDailyMenuServiceImpl.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenDailyMenuServiceImpl.java index 8049b9af..e0da18c7 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenDailyMenuServiceImpl.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenDailyMenuServiceImpl.java @@ -506,16 +506,39 @@ public class CanteenDailyMenuServiceImpl extends ServiceImpl syncChannelSoldFromOrders(Long merchantId, LocalDate mealDate) { + return syncChannelSoldFromOrders(merchantId, mealDate, null); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public R syncChannelSoldFromOrders(Long merchantId, LocalDate mealDate, Long dailyMenuId) { if (merchantId == null || mealDate == null) { return R.failed("商户和用餐日不能为空"); } - List menus = list(Wrappers.lambdaQuery() - .eq(CanteenDailyMenuEntity::getMerchantId, merchantId) - .eq(CanteenDailyMenuEntity::getStartTime, mealDate)); + List menus; + if (dailyMenuId != null) { + CanteenDailyMenuEntity one = getById(dailyMenuId); + if (one == null) { + return R.failed("菜谱行不存在"); + } + if (!Objects.equals(one.getMerchantId(), merchantId)) { + return R.failed("菜谱行不属于当前商户"); + } + if (one.getStartTime() == null || !mealDate.equals(one.getStartTime())) { + return R.failed("菜谱行用餐日与所选日期不一致"); + } + menus = List.of(one); + } + else { + menus = list(Wrappers.lambdaQuery() + .eq(CanteenDailyMenuEntity::getMerchantId, merchantId) + .eq(CanteenDailyMenuEntity::getStartTime, mealDate)); + } if (CollectionUtils.isEmpty(menus)) { return R.ok(0, "当日无菜谱记录"); } + // 单行重算也要拉当日全量净销量:组成单品需叠加「含本菜」套餐单的摊销量 DailyMenuNetSoldQueryDTO query = new DailyMenuNetSoldQueryDTO(); query.setMerchantId(merchantId); query.setMealDate(mealDate); @@ -543,12 +566,16 @@ public class CanteenDailyMenuServiceImpl extends ServiceImpl menuSpuIds = menus.stream().map(CanteenDailyMenuEntity::getSpuId).filter(Objects::nonNull) + // 套餐联动范围:单行时仍按「当日全部菜谱键」判断组成是否已排菜,与全量重算口径一致 + List dayMenus = dailyMenuId == null ? menus + : list(Wrappers.lambdaQuery() + .eq(CanteenDailyMenuEntity::getMerchantId, merchantId) + .eq(CanteenDailyMenuEntity::getStartTime, mealDate)); + Set menuSpuIds = dayMenus.stream().map(CanteenDailyMenuEntity::getSpuId).filter(Objects::nonNull) .collect(Collectors.toSet()); Map> comboMap = canteenSpuService.loadComboItemVos(new ArrayList<>(menuSpuIds)); - Set menuKeys = menus.stream() + Set menuKeys = dayMenus.stream() .filter(m -> m.getHourType() != null && m.getSpuId() != null) .map(m -> m.getHourType() + "|" + m.getSpuId()) .collect(Collectors.toSet()); @@ -612,9 +639,10 @@ public class CanteenDailyMenuServiceImpl extends ServiceImpl mapComboQtyByChildSpuId(Long childSpuId) { + if (childSpuId == null) { + return Collections.emptyMap(); + } + List lines = comboItemMapper.selectList( + Wrappers.lambdaQuery() + .select(CanteenSpuComboItemEntity::getComboSpuId, CanteenSpuComboItemEntity::getQuantity) + .eq(CanteenSpuComboItemEntity::getChildSpuId, childSpuId)); + if (CollUtil.isEmpty(lines)) { + return Collections.emptyMap(); + } + Map result = new LinkedHashMap<>(); + for (CanteenSpuComboItemEntity line : lines) { + if (line == null || line.getComboSpuId() == null) { + continue; + } + int qty = line.getQuantity() == null || line.getQuantity() < 1 ? 1 : line.getQuantity(); + result.merge(line.getComboSpuId(), qty, Integer::sum); + } + return result; + } + @Override public List loadSpuPrintNames(List productIds) { if (CollUtil.isEmpty(productIds)) { diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenDailyMenuMapper.xml b/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenDailyMenuMapper.xml index 06627bbb..4ab54892 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenDailyMenuMapper.xml +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenDailyMenuMapper.xml @@ -99,7 +99,8 @@ IFNULL(t.offline_stock, 600) AS offline_stock, IFNULL(t.online_sold, 0) AS online_sold, IFNULL(t.offline_sold, 0) AS offline_sold, - sp.sales_count, + + IFNULL(t.online_sold, 0) AS sales_count, sp.sort, sp.is_show, c.id AS category_id, @@ -154,7 +155,7 @@ IFNULL(t.offline_stock, 600) AS offline_stock, IFNULL(t.online_sold, 0) AS online_sold, IFNULL(t.offline_sold, 0) AS offline_sold, - sp.sales_count, + IFNULL(t.online_sold, 0) AS sales_count, sp.sort, sp.is_show, c.id AS category_id, @@ -197,7 +198,7 @@ IFNULL(t.offline_stock, 600) AS offline_stock, IFNULL(t.online_sold, 0) AS online_sold, IFNULL(t.offline_sold, 0) AS offline_sold, - sp.sales_count, + IFNULL(t.online_sold, 0) AS sales_count, sp.sort, sp.is_show, c.id AS category_id, @@ -283,7 +284,7 @@ IFNULL(m.offline_stock, 600) AS offline_stock, IFNULL(m.online_sold, 0) AS online_sold, IFNULL(m.offline_sold, 0) AS offline_sold, - s.sales_count, + IFNULL(m.online_sold, 0) AS sales_count, s.pic_url, s.slider_pic_urls, s.introduction, diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOrderDto.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOrderDto.java index 56a07c42..db085951 100644 --- a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOrderDto.java +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOrderDto.java @@ -73,6 +73,12 @@ public class HardOrderDto extends HardOrderEntity implements BaseIsIncludeTreeIn */ private Long productId; + /** + * 购物车商品 SPU ID 集合;用于含套餐父商品的「相关订单」查询(本菜 + 含本菜的套餐)。 + * 与 {@link #productId} 同时有值时取并集语义(XML 用 IN)。 + */ + private List productIds; + private LocalDateTime[] refundTimeList; /** 预计使用日期范围。 */ diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/mapper/order/HardOrderMapper.xml b/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/mapper/order/HardOrderMapper.xml index bc9f0bf3..f84ac3c5 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/mapper/order/HardOrderMapper.xml +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/mapper/order/HardOrderMapper.xml @@ -239,12 +239,22 @@ and a.appt_use_date between #{dto.apptUseDateTimeList[0]} and #{dto.apptUseDateTimeList[1]} - + and exists ( select 1 from hard_car c where c.parent_car_id = a.parent_car_id and c.del_flag = '0' - and c.product_id = #{dto.productId} + + + and c.product_id in + + #{v} + + + + and c.product_id = #{dto.productId} + + )