From de216a35827a4b9317b28ab03b313b1948801c72 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Wed, 11 Mar 2026 18:49:24 +0800 Subject: [PATCH] =?UTF-8?q?=E8=8F=9C=E5=93=81=E8=BD=AC=E6=8D=A2=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...emoteCanteenProductionTemplateService.java | 30 +++ .../dto/erp/CanteenErpMaterialSaveDTO.java | 2 + .../entity/CanteenErpMaterialEntity.java | 6 + ...CanteenProductionTemplateDetailEntity.java | 6 + .../CanteenProductionTemplateEntity.java | 14 ++ .../canteen/vo/app/CanteenOnlineSpuAppVO.java | 6 + .../canteen/vo/erp/CanteenErpMaterialVO.java | 2 + .../vo/erp/CanteenOnlineSpuSimpleVO.java | 21 ++ .../vo/erp/ProductionTemplateDetailVO.java | 2 + .../CanteenErpMaterialController.java | 14 +- .../CanteenOnlineSpuController.java | 16 ++ .../CanteenProductionTemplateController.java | 16 +- .../service/CanteenErpMaterialService.java | 6 +- .../service/CanteenOnlineSpuService.java | 6 + .../CanteenProductionTemplateService.java | 14 ++ .../impl/CanteenErpMaterialServiceImpl.java | 100 +++++--- .../impl/CanteenOnlineSpuServiceImpl.java | 19 ++ .../CanteenProductionTemplateServiceImpl.java | 93 +++++++- .../mapper/CanteenErpMaterialMapper.xml | 5 + .../CanteenProductionTemplateDetailMapper.xml | 1 + .../CanteenProductionTemplateMapper.xml | 1 + .../order/HardOnlineCanteenStatsQueryDto.java | 21 ++ .../HardOnlineCanteenMaterialUsageVo.java | 24 ++ .../order/HardOnlineCanteenNutritionVo.java | 15 ++ .../vo/order/HardOnlineCanteenStatsVo.java | 32 +++ .../controller/order/HardOrderController.java | 25 ++ .../HardOnlineCanteenStatsService.java | 17 ++ .../HardOnlineCanteenStatsServiceImpl.java | 217 ++++++++++++++++++ .../mapper/order/HardOrderMapper.xml | 13 ++ 29 files changed, 689 insertions(+), 55 deletions(-) create mode 100644 pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/api/feign/RemoteCanteenProductionTemplateService.java create mode 100644 pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/CanteenOnlineSpuSimpleVO.java create mode 100644 pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOnlineCanteenStatsQueryDto.java create mode 100644 pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenMaterialUsageVo.java create mode 100644 pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenNutritionVo.java create mode 100644 pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenStatsVo.java create mode 100644 pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOnlineCanteenStatsService.java create mode 100644 pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOnlineCanteenStatsServiceImpl.java diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/api/feign/RemoteCanteenProductionTemplateService.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/api/feign/RemoteCanteenProductionTemplateService.java new file mode 100644 index 000000000..0db85939b --- /dev/null +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/api/feign/RemoteCanteenProductionTemplateService.java @@ -0,0 +1,30 @@ +package com.bsd.pjcloud.canteen.api.feign; + +import com.bsd.pjcloud.canteen.vo.erp.ProductTemplateVO; +import com.bsd.pjcloud.common.core.constant.ServiceNameConstants; +import com.bsd.pjcloud.common.core.util.R; +import com.bsd.pjcloud.common.feign.annotation.NoToken; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; + +/** + * 加工模版远程服务(用于线上订餐原料转换) + */ +@FeignClient(contextId = "remoteCanteenProductionTemplateService", value = ServiceNameConstants.CANTEEN_SERVICE) +public interface RemoteCanteenProductionTemplateService { + + /** + * 根据菜品id列表获取加工模版详情 + */ + @PostMapping("/canteenProductionTemplate/inner/getDetailsByDishIds") + R> getDetailsByDishIds(@RequestBody List dishIds); + + /** + * 根据菜品id列表获取线上加工模版详情(仅 template_type=2,用于线上订餐统计) + */ + @PostMapping("/canteenProductionTemplate/inner/getDetailsByDishIdsForOnline") + R> getDetailsByDishIdsForOnline(@RequestBody List dishIds); +} diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/dto/erp/CanteenErpMaterialSaveDTO.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/dto/erp/CanteenErpMaterialSaveDTO.java index 21fe8a32d..0a126a530 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/dto/erp/CanteenErpMaterialSaveDTO.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/dto/erp/CanteenErpMaterialSaveDTO.java @@ -18,6 +18,8 @@ public class CanteenErpMaterialSaveDTO { @Schema(description="商品单位") private String unit; + @Schema(description="食材类型:1-线下,2-线上") + private Integer materialType; /** * 期初数量 diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenErpMaterialEntity.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenErpMaterialEntity.java index 01170ef8d..1dca6d6ab 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenErpMaterialEntity.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenErpMaterialEntity.java @@ -41,6 +41,12 @@ public class CanteenErpMaterialEntity extends Model { @Schema(description="商品单位") private String unit; + /** + * 食材类型:1-线下,2-线上 + */ + @Schema(description="食材类型:1-线下,2-线上") + private Integer materialType; + /** * 部门id */ diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenProductionTemplateDetailEntity.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenProductionTemplateDetailEntity.java index 41d737648..74ebe4b57 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenProductionTemplateDetailEntity.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenProductionTemplateDetailEntity.java @@ -59,6 +59,12 @@ public class CanteenProductionTemplateDetailEntity extends Model canteenProductionTemplateDetailList; + + /** + * 菜品名称(回显用,不落库;根据 templateType 从 CanteenSpu 或 CanteenOnlineSpu 解析) + */ + @ExcelIgnore + @TableField(exist = false) + @Schema(description = "菜品名称") + private String dishName; } \ No newline at end of file diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/app/CanteenOnlineSpuAppVO.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/app/CanteenOnlineSpuAppVO.java index 131f6055f..c64477526 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/app/CanteenOnlineSpuAppVO.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/app/CanteenOnlineSpuAppVO.java @@ -122,6 +122,12 @@ public class CanteenOnlineSpuAppVO { @Schema(description="部门id") private Long deptId; + /** + * 关联线下菜品id(canteen_spu.id),用于原料转换 + */ + @Schema(description="关联线下菜品id") + private Long linkSpuId; + /** * 创建时间 diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/CanteenErpMaterialVO.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/CanteenErpMaterialVO.java index 983e28509..22337099b 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/CanteenErpMaterialVO.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/CanteenErpMaterialVO.java @@ -20,6 +20,8 @@ public class CanteenErpMaterialVO { @Schema(description="商品单位") private String unit; + @Schema(description="食材类型:1-线下,2-线上") + private Integer materialType; /** * 期初数量 diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/CanteenOnlineSpuSimpleVO.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/CanteenOnlineSpuSimpleVO.java new file mode 100644 index 000000000..b4134314f --- /dev/null +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/CanteenOnlineSpuSimpleVO.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.canteen.vo.erp; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "线上菜品简略VO,用于模板选择弹窗") +public class CanteenOnlineSpuSimpleVO { + + @Schema(description = "id") + private Long id; + + @Schema(description = "菜品名称") + private String name; + + @Schema(description = "菜品封面图") + private String picUrl; + + @Schema(description = "关联线下菜品id") + private Long linkSpuId; +} diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/ProductionTemplateDetailVO.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/ProductionTemplateDetailVO.java index bfb605c5b..fa582d45b 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/ProductionTemplateDetailVO.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/erp/ProductionTemplateDetailVO.java @@ -59,4 +59,6 @@ public class ProductionTemplateDetailVO{ @Schema(description="单位") private String unit; + @Schema(description="营养元素描述") + private String nutritionDesc; } \ No newline at end of file diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenErpMaterialController.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenErpMaterialController.java index dfc226e9f..1b012ab65 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenErpMaterialController.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenErpMaterialController.java @@ -49,7 +49,7 @@ public class CanteenErpMaterialController { * @param canteenErpMaterial 原料表 * @return */ - @Operation(summary = "分页查询" , description = "分页查询" ) + @Operation(summary = "分页查询" , description = "分页查询,支持按食材类型筛选" ) @GetMapping("/page" ) @PreAuthorize("@pms.hasPermission('canteen_canteenErpMaterial_view')" ) public R getCanteenErpMaterialPage(@ParameterObject Page page, @ParameterObject CanteenErpMaterialEntity canteenErpMaterial) { @@ -127,13 +127,15 @@ public class CanteenErpMaterialController { /** * erp选择食材分页数据 - * 分页查询 * @param page 分页对象 - * @return + * @param name 食材名称 + * @param materialType 食材类型:1-线下,2-线上,不传默认线下 */ - @Operation(summary = "选择食材分页数据" , description = "选择食材分页数据" ) + @Operation(summary = "选择食材分页数据" , description = "选择食材分页数据,materialType不传默认线下" ) @GetMapping("/erpMaterialPage" ) - public R getErpMaterialPage(@ParameterObject Page page, @RequestParam(value = "name",required = false)String name) { - return R.ok(canteenErpMaterialService.getErpMaterialPage(page, name)); + public R getErpMaterialPage(@ParameterObject Page page, + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "materialType", required = false) Integer materialType) { + return R.ok(canteenErpMaterialService.getErpMaterialPage(page, name, materialType)); } } \ No newline at end of file diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenOnlineSpuController.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenOnlineSpuController.java index 2c8d757fb..06ee646ac 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenOnlineSpuController.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenOnlineSpuController.java @@ -45,6 +45,22 @@ public class CanteenOnlineSpuController { private final CanteenOnlineSpuService canteenOnlineSpuService; + /** + * 模板选择线上菜品分页(用于加工模版选择菜品弹窗) + * 类似 /canteen/canteenSpu/getCanteenSpuSimplePage + * + * @param page 分页对象 + * @param canteenOnlineSpu 查询条件(name、categoryId) + * @return + */ + @Operation(summary = "模板选择线上菜品分页", description = "用于加工模版选择线上菜品弹窗,支持按名称、分类筛选") + @GetMapping("/getCanteenOnlineSpuSimplePage") + @PreAuthorize("@pms.hasPermission('canteen_canteenOnlineSpu_view')") + public R> getCanteenOnlineSpuSimplePage( + @ParameterObject Page page, @ParameterObject CanteenOnlineSpuEntity canteenOnlineSpu) { + return R.ok(canteenOnlineSpuService.getCanteenOnlineSpuSimplePageScope(page, canteenOnlineSpu)); + } + /** * 分页查询 * diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenProductionTemplateController.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenProductionTemplateController.java index eecdaa44a..94cbc2d0f 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenProductionTemplateController.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/controller/CanteenProductionTemplateController.java @@ -10,6 +10,7 @@ import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.log.annotation.SysLog; import com.bsd.pjcloud.canteen.entity.CanteenProductionTemplateEntity; import com.bsd.pjcloud.canteen.service.CanteenProductionTemplateService; +import com.bsd.pjcloud.common.security.annotation.Inner; import com.bsd.pjcloud.common.security.util.SecurityUtils; import org.springframework.security.access.prepost.PreAuthorize; import com.bsd.pjcloud.common.excel.annotation.ResponseExcel; @@ -50,7 +51,8 @@ public class CanteenProductionTemplateController { @PreAuthorize("@pms.hasPermission('canteen_canteenProductionTemplate_view')" ) public R getCanteenProductionTemplatePage(@ParameterObject Page page, @ParameterObject CanteenProductionTemplateEntity canteenProductionTemplate) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); - wrapper.eq(StrUtil.isNotBlank(canteenProductionTemplate.getTemplateName()),CanteenProductionTemplateEntity::getTemplateName,canteenProductionTemplate.getTemplateName()); + wrapper.eq(StrUtil.isNotBlank(canteenProductionTemplate.getTemplateName()),CanteenProductionTemplateEntity::getTemplateName,canteenProductionTemplate.getTemplateName()) + .eq(canteenProductionTemplate.getTemplateType() != null, CanteenProductionTemplateEntity::getTemplateType, canteenProductionTemplate.getTemplateType()); return R.ok(canteenProductionTemplateService.pageScope(page, wrapper)); } @@ -129,4 +131,16 @@ public class CanteenProductionTemplateController { public R getSelectTemplatePage(@ParameterObject Page page, @RequestParam(value = "name",required = false)String name) { return R.ok(canteenProductionTemplateService.getSelectTemplatePageScope(page, name)); } + + @Operation(summary = "根据菜品id列表获取模版详情(内部)") + @PostMapping("/inner/getDetailsByDishIds") + public R> getDetailsByDishIds(@RequestBody List dishIds) { + return R.ok(canteenProductionTemplateService.getDetailsByDishIds(dishIds)); + } + + @Operation(summary = "根据菜品id列表获取线上模版详情(内部)", description = "仅返回 template_type=2 的模版,用于线上订餐统计") + @PostMapping("/inner/getDetailsByDishIdsForOnline") + public R> getDetailsByDishIdsForOnline(@RequestBody List dishIds) { + return R.ok(canteenProductionTemplateService.getDetailsByDishIdsForOnline(dishIds)); + } } \ No newline at end of file diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenErpMaterialService.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenErpMaterialService.java index 676682996..584e8c902 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenErpMaterialService.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenErpMaterialService.java @@ -7,6 +7,7 @@ import com.bsd.pjcloud.canteen.dto.erp.CanteenErpMaterialEditorDTO; import com.bsd.pjcloud.canteen.dto.erp.CanteenErpMaterialSaveDTO; import com.bsd.pjcloud.canteen.entity.CanteenErpMaterialEntity; import com.bsd.pjcloud.canteen.vo.erp.CanteenErpMaterialVO; +import com.bsd.pjcloud.canteen.vo.erp.ErpMaterialPageVo; public interface CanteenErpMaterialService extends IService { @@ -37,10 +38,11 @@ public interface CanteenErpMaterialService extends IService getErpMaterialPage(Page page, String name, Integer materialType); } \ No newline at end of file diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenOnlineSpuService.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenOnlineSpuService.java index f97770add..1e0272dac 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenOnlineSpuService.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenOnlineSpuService.java @@ -7,12 +7,18 @@ import com.bsd.pjcloud.canteen.dto.CanteenOnlineSpuUpdateStockReqDTO; import com.bsd.pjcloud.canteen.dto.canteenonline.CanteenOnlineSpuSaveDto; import com.bsd.pjcloud.canteen.entity.CanteenOnlineSpuEntity; import com.bsd.pjcloud.canteen.vo.APPOnlineSpuVO; +import com.bsd.pjcloud.canteen.vo.erp.CanteenOnlineSpuSimpleVO; import com.bsd.pjcloud.common.core.util.R; import java.util.List; public interface CanteenOnlineSpuService extends IService { + /** + * 模板选择线上菜品分页(简化数据,用于选择弹窗) + */ + Page getCanteenOnlineSpuSimplePageScope(Page page, CanteenOnlineSpuEntity canteenOnlineSpu); + /** * 根据分类id获取商品列表 diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenProductionTemplateService.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenProductionTemplateService.java index 257fe11b2..89f0fd1f8 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenProductionTemplateService.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/CanteenProductionTemplateService.java @@ -20,6 +20,20 @@ public interface CanteenProductionTemplateService extends MPJDeepService getDetailsByDishIds(java.util.List dishIds); + + /** + * 根据菜品id列表获取线上加工模版详情(仅 template_type=2) + * @param dishIds 菜品id列表(canteen_online_spu.link_spu_id) + * @return 模版详情列表 + */ + java.util.List getDetailsByDishIdsForOnline(java.util.List dishIds); + /** * 分页 * @param page diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenErpMaterialServiceImpl.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenErpMaterialServiceImpl.java index 5187415ae..1c0c75825 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenErpMaterialServiceImpl.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenErpMaterialServiceImpl.java @@ -20,6 +20,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -43,18 +44,23 @@ public class CanteenErpMaterialServiceImpl extends ServiceImpl canteenStockEntityLambdaQueryWrapper = new LambdaQueryWrapper<>(); - canteenStockEntityLambdaQueryWrapper.eq(CanteenStockEntity::getItemId, id); - CanteenStockEntity sourceCanteenStockEntity = canteenStockMapper.selectOne(canteenStockEntityLambdaQueryWrapper); - - CanteenStockEntity canteenStockEntity = new CanteenStockEntity(); - canteenStockEntity.setItemId(canteenErpMaterialEntity.getId()); - canteenStockEntity.setBaseStock(canteenErpMaterialEditorDTO.getBaseStock()); - canteenStockEntity.setCurrentStock(canteenErpMaterialEditorDTO.getBaseStock()+(sourceCanteenStockEntity.getCurrentStock()-sourceCanteenStockEntity.getBaseStock())); - canteenStockEntity.setInventoryUpperLimit(canteenErpMaterialEditorDTO.getInventoryUpperLimit()); - canteenStockEntity.setInventoryLowerLimit(canteenErpMaterialEditorDTO.getInventoryLowerLimit()); int i = baseMapper.updateById(canteenErpMaterialEntity); - canteenStockMapper.update(canteenStockEntity, - new LambdaQueryWrapper().eq(CanteenStockEntity::getItemId, id)); + // 线上食材(materialType=2)无库存,不更新 + int materialType = canteenErpMaterialEditorDTO.getMaterialType() != null ? canteenErpMaterialEditorDTO.getMaterialType() : 1; + if (materialType == 1) { + LambdaQueryWrapper canteenStockEntityLambdaQueryWrapper = new LambdaQueryWrapper<>(); + canteenStockEntityLambdaQueryWrapper.eq(CanteenStockEntity::getItemId, id); + CanteenStockEntity sourceCanteenStockEntity = canteenStockMapper.selectOne(canteenStockEntityLambdaQueryWrapper); + if (sourceCanteenStockEntity != null) { + CanteenStockEntity canteenStockEntity = new CanteenStockEntity(); + canteenStockEntity.setItemId(canteenErpMaterialEntity.getId()); + canteenStockEntity.setBaseStock(canteenErpMaterialEditorDTO.getBaseStock()); + canteenStockEntity.setCurrentStock(canteenErpMaterialEditorDTO.getBaseStock() + (sourceCanteenStockEntity.getCurrentStock() - sourceCanteenStockEntity.getBaseStock())); + canteenStockEntity.setInventoryUpperLimit(canteenErpMaterialEditorDTO.getInventoryUpperLimit()); + canteenStockEntity.setInventoryLowerLimit(canteenErpMaterialEditorDTO.getInventoryLowerLimit()); + canteenStockMapper.update(canteenStockEntity, + new LambdaQueryWrapper().eq(CanteenStockEntity::getItemId, id)); + } + } return i; } @@ -94,27 +106,39 @@ public class CanteenErpMaterialServiceImpl extends ServiceImpl canteenStockEntityLambdaQueryWrapper = new LambdaQueryWrapper<>(); - canteenStockEntityLambdaQueryWrapper.eq(CanteenStockEntity::getItemId, id); - CanteenStockEntity sourceCanteenStockEntity = canteenStockMapper.selectOne(canteenStockEntityLambdaQueryWrapper); - CanteenErpMaterialVO canteenErpMaterialVO = new CanteenErpMaterialVO(); canteenErpMaterialVO.setId(canteenErpMaterialEntity.getId()); canteenErpMaterialVO.setName(canteenErpMaterialEntity.getName()); canteenErpMaterialVO.setUnit(canteenErpMaterialEntity.getUnit()); - canteenErpMaterialVO.setBaseStock(sourceCanteenStockEntity.getBaseStock()); - canteenErpMaterialVO.setInventoryUpperLimit(sourceCanteenStockEntity.getInventoryUpperLimit()); - canteenErpMaterialVO.setInventoryLowerLimit(sourceCanteenStockEntity.getInventoryLowerLimit()); - canteenErpMaterialVO.setCurrentStock(sourceCanteenStockEntity.getCurrentStock()); canteenErpMaterialVO.setPurchasePrice(canteenErpMaterialEntity.getPurchasePrice()); canteenErpMaterialVO.setCategoryId(canteenErpMaterialEntity.getCategoryId()); + canteenErpMaterialVO.setMaterialType(canteenErpMaterialEntity.getMaterialType()); + // 线上食材无库存,仅线下查询库存 + int materialType = canteenErpMaterialEntity.getMaterialType() != null ? canteenErpMaterialEntity.getMaterialType() : 1; + if (materialType == 1) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(CanteenStockEntity::getItemId, id); + CanteenStockEntity stock = canteenStockMapper.selectOne(wrapper); + if (stock != null) { + canteenErpMaterialVO.setBaseStock(stock.getBaseStock()); + canteenErpMaterialVO.setInventoryUpperLimit(stock.getInventoryUpperLimit()); + canteenErpMaterialVO.setInventoryLowerLimit(stock.getInventoryLowerLimit()); + canteenErpMaterialVO.setCurrentStock(stock.getCurrentStock()); + } + } else { + canteenErpMaterialVO.setBaseStock(0D); + canteenErpMaterialVO.setCurrentStock(0D); + canteenErpMaterialVO.setInventoryUpperLimit(0); + canteenErpMaterialVO.setInventoryLowerLimit(0); + } return canteenErpMaterialVO; } @Override - public Page getErpMaterialPage(Page page, String name) { + public Page getErpMaterialPage(Page page, String name, Integer materialType) { LambdaQueryWrapper smErpUnitEntityLambdaQueryWrapper = new LambdaQueryWrapper<>(); - smErpUnitEntityLambdaQueryWrapper.like(StringUtils.isNotBlank(name), CanteenErpMaterialEntity::getName, name); + smErpUnitEntityLambdaQueryWrapper.like(StringUtils.isNotBlank(name), CanteenErpMaterialEntity::getName, name) + .eq(CanteenErpMaterialEntity::getMaterialType, materialType != null ? materialType : 1); Page spuPage = baseMapper.selectPageByScope(page, smErpUnitEntityLambdaQueryWrapper, DataScope.of()); // 将 SmErpSpuEntity 转换为 SmErpPageScopeVo @@ -122,22 +146,22 @@ public class CanteenErpMaterialServiceImpl extends ServiceImpl BeanUtils.toBean(entity, ErpMaterialPageVo.class)) .collect(Collectors.toList()); - List materialIds = voList.stream().map(vo -> vo.getId()).collect(Collectors.toList()); + List materialIds = voList.stream().map(ErpMaterialPageVo::getId).collect(Collectors.toList()); - // 批量查询库存信息 - List stocks = canteenStockMapper.selectList( + // 批量查询库存信息(materialIds 为空时跳过,避免 IN () 语法错误) + List stocks = materialIds.isEmpty() ? Collections.emptyList() : canteenStockMapper.selectList( new LambdaQueryWrapper() - .in(CanteenStockEntity::getItemId, materialIds)); + .in(CanteenStockEntity::getItemId, materialIds)); // 建立SPU ID与库存的映射关系 - Map stockMap = stocks.stream() + Map stockMap = stocks.stream() .collect(Collectors.toMap(CanteenStockEntity::getItemId, smErpStockEntity -> smErpStockEntity)); voList.stream().forEach(vo -> { - //库存 - CanteenStockEntity smErpStockEntity = stockMap.get(vo.getId()); - vo.setStock(smErpStockEntity != null ? smErpStockEntity.getCurrentStock() : 0); + CanteenStockEntity stock = stockMap.get(vo.getId()); + Double currentStock = (stock != null && stock.getCurrentStock() != null) ? stock.getCurrentStock() : 0D; + vo.setStock(currentStock); }); // 创建新的 Page 对象并设置数据 diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenOnlineSpuServiceImpl.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenOnlineSpuServiceImpl.java index c4291d43c..75f9b3b8e 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenOnlineSpuServiceImpl.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenOnlineSpuServiceImpl.java @@ -16,6 +16,7 @@ import com.bsd.pjcloud.canteen.mapper.CanteenOnlineCategoryMapper; import com.bsd.pjcloud.canteen.mapper.CanteenOnlineSpuMapper; import com.bsd.pjcloud.canteen.service.CanteenOnlineSpuService; import com.bsd.pjcloud.canteen.vo.APPOnlineSpuVO; +import com.bsd.pjcloud.canteen.vo.erp.CanteenOnlineSpuSimpleVO; import com.bsd.pjcloud.common.core.util.BeanUtils; import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.data.datascope.DataScope; @@ -33,6 +34,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.Objects; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; /** * 在线点餐spu @@ -166,6 +168,23 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl getCanteenOnlineSpuSimplePageScope(Page page, CanteenOnlineSpuEntity canteenOnlineSpu) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(StrUtil.isNotBlank(canteenOnlineSpu.getName()), CanteenOnlineSpuEntity::getName, canteenOnlineSpu.getName()) + .eq(Objects.nonNull(canteenOnlineSpu.getCategoryId()), CanteenOnlineSpuEntity::getCategoryId, canteenOnlineSpu.getCategoryId()) + .orderByAsc(CanteenOnlineSpuEntity::getSort).orderByDesc(CanteenOnlineSpuEntity::getId); + Page pageData = baseMapper.selectPageByScope(page, wrapper, DataScope.of()); + List voList = BeanUtils.toBean(pageData.getRecords(), CanteenOnlineSpuSimpleVO.class); + Page resultPage = new Page<>(); + resultPage.setRecords(voList); + resultPage.setCurrent(pageData.getCurrent()); + resultPage.setPages(pageData.getPages()); + resultPage.setSize(pageData.getSize()); + resultPage.setTotal(pageData.getTotal()); + return resultPage; + } + @Override public Object pageScope(Page page, LambdaQueryWrapper wrapper) { Page pageData = baseMapper.selectPageByScope(page, wrapper, DataScope.of()); diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenProductionTemplateServiceImpl.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenProductionTemplateServiceImpl.java index 2147d855b..89601b5ce 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenProductionTemplateServiceImpl.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/service/impl/CanteenProductionTemplateServiceImpl.java @@ -6,8 +6,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bsd.pjcloud.canteen.entity.CanteenErpMaterialEntity; import com.bsd.pjcloud.canteen.entity.CanteenProductionTemplateEntity; +import com.bsd.pjcloud.canteen.entity.CanteenOnlineSpuEntity; import com.bsd.pjcloud.canteen.entity.CanteenSpuEntity; import com.bsd.pjcloud.canteen.mapper.CanteenErpMaterialMapper; +import com.bsd.pjcloud.canteen.mapper.CanteenOnlineSpuMapper; import com.bsd.pjcloud.canteen.mapper.CanteenProductionTemplateMapper; import com.bsd.pjcloud.canteen.mapper.CanteenSpuMapper; import com.bsd.pjcloud.canteen.service.CanteenProductionTemplateService; @@ -38,8 +40,11 @@ import java.util.stream.Collectors; public class CanteenProductionTemplateServiceImpl extends ServiceImpl implements CanteenProductionTemplateService { private final CanteenProductionTemplateDetailMapper canteenProductionTemplateDetailMapper; private final CanteenSpuMapper canteenSpuMapper; + private final CanteenOnlineSpuMapper canteenOnlineSpuMapper; private final CanteenErpMaterialMapper canteenErpMaterialMapper; + private static final int TEMPLATE_TYPE_ONLINE = 2; + @Override @Transactional(rollbackFor = Exception.class) public Boolean saveDeep(CanteenProductionTemplateEntity canteenProductionTemplate) { @@ -85,29 +90,101 @@ public class CanteenProductionTemplateServiceImpl extends ServiceImpl canteenProductionTemplateDetailEntityLambdaQueryWrapper = new LambdaQueryWrapper<>(); canteenProductionTemplateDetailEntityLambdaQueryWrapper.eq(CanteenProductionTemplateDetailEntity::getTemplateId, id); List canteenProductionTemplateDetailEntities = canteenProductionTemplateDetailMapper.selectList(canteenProductionTemplateDetailEntityLambdaQueryWrapper); ProductTemplateVO bean = BeanUtils.toBean(canteenProductionTemplateEntity, ProductTemplateVO.class); - bean.setDishName(canteenSpuEntity.getName()); + bean.setDishName(dishName); List productionTemplateDetailVOList= BeanUtils.toBean(canteenProductionTemplateDetailEntities, ProductionTemplateDetailVO.class); for (ProductionTemplateDetailVO productionTemplateDetailVO : productionTemplateDetailVOList) { Long materialId = productionTemplateDetailVO.getMaterialId(); - CanteenErpMaterialEntity canteenErpMaterialEntity = canteenErpMaterialMapper.selectById(materialId); - productionTemplateDetailVO.setMaterialName(canteenErpMaterialEntity.getName()); - productionTemplateDetailVO.setUnit(canteenErpMaterialEntity.getUnit()); + CanteenErpMaterialEntity material = canteenErpMaterialMapper.selectById(materialId); + if (material != null) { + productionTemplateDetailVO.setMaterialName(material.getName()); + productionTemplateDetailVO.setUnit(material.getUnit()); + } } bean.setCanteenProductionTemplateDetailList(productionTemplateDetailVOList); return bean; } + @Override + public List getDetailsByDishIds(List dishIds) { + if (CollUtil.isEmpty(dishIds)) { + return Collections.emptyList(); + } + List templates = baseMapper.selectList( + Wrappers.lambdaQuery().in(CanteenProductionTemplateEntity::getDishId, dishIds)); + if (CollUtil.isEmpty(templates)) { + return Collections.emptyList(); + } + return buildTemplateDetailList(templates); + } + + /** 根据模板类型解析菜品名称:线上查 CanteenOnlineSpu,线下查 CanteenSpu */ + private String resolveDishName(Integer templateType, Long dishId) { + if (dishId == null) return ""; + if (TEMPLATE_TYPE_ONLINE == templateType) { + CanteenOnlineSpuEntity onlineSpu = canteenOnlineSpuMapper.selectById(dishId); + if (onlineSpu != null) return onlineSpu.getName(); + // 兼容:线上模板可能存的是 linkSpuId,回退查线下 + } + CanteenSpuEntity spu = canteenSpuMapper.selectById(dishId); + return spu != null ? spu.getName() : ""; + } + + @Override + public List getDetailsByDishIdsForOnline(List dishIds) { + if (CollUtil.isEmpty(dishIds)) { + return Collections.emptyList(); + } + List templates = baseMapper.selectList( + Wrappers.lambdaQuery() + .in(CanteenProductionTemplateEntity::getDishId, dishIds) + .eq(CanteenProductionTemplateEntity::getTemplateType, TEMPLATE_TYPE_ONLINE)); + if (CollUtil.isEmpty(templates)) { + return Collections.emptyList(); + } + return buildTemplateDetailList(templates); + } + + private List buildTemplateDetailList(List templates) { + List templateIds = templates.stream().map(CanteenProductionTemplateEntity::getId).collect(Collectors.toList()); + List details = canteenProductionTemplateDetailMapper.selectList( + Wrappers.lambdaQuery().in(CanteenProductionTemplateDetailEntity::getTemplateId, templateIds)); + Set dishIdSet = templates.stream().map(CanteenProductionTemplateEntity::getDishId).collect(Collectors.toSet()); + Set materialIds = details.stream().map(CanteenProductionTemplateDetailEntity::getMaterialId).collect(Collectors.toSet()); + Map dishMap = CollUtil.isEmpty(dishIdSet) ? Collections.emptyMap() + : canteenSpuMapper.selectByIds(dishIdSet).stream().collect(Collectors.toMap(CanteenSpuEntity::getId, e -> e)); + Map materialMap = CollUtil.isEmpty(materialIds) ? Collections.emptyMap() + : canteenErpMaterialMapper.selectByIds(materialIds).stream().collect(Collectors.toMap(CanteenErpMaterialEntity::getId, e -> e)); + Map> detailMap = details.stream().collect(Collectors.groupingBy(CanteenProductionTemplateDetailEntity::getTemplateId)); + List result = new ArrayList<>(); + for (CanteenProductionTemplateEntity t : templates) { + ProductTemplateVO vo = BeanUtils.toBean(t, ProductTemplateVO.class); + vo.setDishName(dishMap.getOrDefault(t.getDishId(), new CanteenSpuEntity()).getName()); + List detailVOList = BeanUtils.toBean(detailMap.getOrDefault(t.getId(), Collections.emptyList()), ProductionTemplateDetailVO.class); + for (ProductionTemplateDetailVO d : detailVOList) { + CanteenErpMaterialEntity m = materialMap.get(d.getMaterialId()); + if (m != null) { + d.setMaterialName(m.getName()); + d.setUnit(m.getUnit()); + } + } + vo.setCanteenProductionTemplateDetailList(detailVOList); + result.add(vo); + } + return result; + } + @Override public Object pageScope(Page page, LambdaQueryWrapper wrapper) { - Page pageData = baseMapper.selectPageByScope(page, wrapper, DataScope.of()); -// pageData.getRecords().forEach(item->{ -// }); + Page pageData = baseMapper.selectPageByScope(page, wrapper, DataScope.of()); + pageData.getRecords().forEach(item -> + item.setDishName(resolveDishName(item.getTemplateType(), item.getDishId()))); return pageData; } diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenErpMaterialMapper.xml b/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenErpMaterialMapper.xml index aa126d214..0433c077e 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenErpMaterialMapper.xml +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenErpMaterialMapper.xml @@ -7,6 +7,7 @@ + @@ -22,6 +23,7 @@ m.id, m.name, m.unit, + m.material_type AS materialType, m.category_id, m.purchase_price, s.base_stock AS baseStock, @@ -36,6 +38,9 @@ and m.name like concat('%',#{canteenErpMaterial.name},'%') + + and m.material_type = #{canteenErpMaterial.materialType} + \ No newline at end of file diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenProductionTemplateDetailMapper.xml b/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenProductionTemplateDetailMapper.xml index c7d65b365..ba3613ebd 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenProductionTemplateDetailMapper.xml +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenProductionTemplateDetailMapper.xml @@ -10,6 +10,7 @@ + diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenProductionTemplateMapper.xml b/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenProductionTemplateMapper.xml index fee5abfc2..a14dbbbdb 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenProductionTemplateMapper.xml +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/resources/mapper/CanteenProductionTemplateMapper.xml @@ -7,6 +7,7 @@ + diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOnlineCanteenStatsQueryDto.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOnlineCanteenStatsQueryDto.java new file mode 100644 index 000000000..bb97bf160 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOnlineCanteenStatsQueryDto.java @@ -0,0 +1,21 @@ +package com.bsd.pjcloud.hard.api.dto.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 线上订餐统计查询参数 + */ +@Data +@Schema(description = "线上订餐统计查询") +public class HardOnlineCanteenStatsQueryDto { + + @Schema(description = "支付时间范围") + private LocalDateTime[] payTimeList; + + @Schema(description = "商户(食堂)id列表") + private List mchIds; +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenMaterialUsageVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenMaterialUsageVo.java new file mode 100644 index 000000000..fb3638b66 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenMaterialUsageVo.java @@ -0,0 +1,24 @@ +package com.bsd.pjcloud.hard.api.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 原料用量明细 + */ +@Data +@Schema(description = "原料用量明细") +public class HardOnlineCanteenMaterialUsageVo { + + @Schema(description = "原料id") + private Long materialId; + + @Schema(description = "原料名称") + private String materialName; + + @Schema(description = "用量") + private Double usage; + + @Schema(description = "单位") + private String unit; +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenNutritionVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenNutritionVo.java new file mode 100644 index 000000000..83910b598 --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenNutritionVo.java @@ -0,0 +1,15 @@ +package com.bsd.pjcloud.hard.api.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 营养元素汇总(原料营养描述合集) + */ +@Data +@Schema(description = "营养元素汇总") +public class HardOnlineCanteenNutritionVo { + + @Schema(description = "营养描述(各原料营养描述的汇总,用户自定义文案)") + private String nutritionDesc; +} diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenStatsVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenStatsVo.java new file mode 100644 index 000000000..851e3ca8f --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardOnlineCanteenStatsVo.java @@ -0,0 +1,32 @@ +package com.bsd.pjcloud.hard.api.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 线上订餐统计结果(按食堂汇总) + */ +@Data +@Schema(description = "线上订餐统计-按食堂") +public class HardOnlineCanteenStatsVo { + + @Schema(description = "食堂(商户)id") + private Long merchantId; + + @Schema(description = "食堂名称") + private String merchantName; + + @Schema(description = "订单数") + private Long orderCount = 0L; + + @Schema(description = "菜品份数合计") + private Long totalDishCount = 0L; + + @Schema(description = "原料用量明细") + private List materialUsages; + + @Schema(description = "营养元素汇总") + private HardOnlineCanteenNutritionVo nutritionSummary; +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/order/HardOrderController.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/order/HardOrderController.java index fb39b1b5b..73ad417a4 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/order/HardOrderController.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/order/HardOrderController.java @@ -30,6 +30,7 @@ import com.bsd.pjcloud.hard.api.constant.order.HardPayTypeEnum; import com.bsd.pjcloud.hard.api.dto.app.HardAppCreateOrderScancode; import com.bsd.pjcloud.hard.api.dto.hard.CurrentUserHardTypeInfoDto; import com.bsd.pjcloud.hard.api.dto.hard.HardOfflinePayDto; +import com.bsd.pjcloud.hard.api.dto.order.HardOnlineCanteenStatsQueryDto; import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto; import com.bsd.pjcloud.hard.api.dto.order.HardOrderPreferencesDto; import com.bsd.pjcloud.hard.api.dto.order.act.HardCreateActOrderDto; @@ -39,7 +40,9 @@ import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity; import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo; import com.bsd.pjcloud.hard.api.vo.order.excel.HardOrderExcelVo; import com.bsd.pjcloud.hard.mapper.order.HardOrderMapper; +import com.bsd.pjcloud.hard.api.vo.order.HardOnlineCanteenStatsVo; import com.bsd.pjcloud.hard.service.HardManagerService; +import com.bsd.pjcloud.hard.service.HardOnlineCanteenStatsService; import com.bsd.pjcloud.hard.service.HardOrderService; import com.bsd.pjcloud.hard.service.HardOrderSyncService; import com.bsd.pjcloud.wallet.api.constant.WalletTypeEnum; @@ -78,6 +81,7 @@ public class HardOrderController { private final HardOrderService hardwareOrderService; private final HardManagerService hardManagerService; + private final HardOnlineCanteenStatsService hardOnlineCanteenStatsService; private final HardOrderSyncService hardOrderSyncService; private final HardOrderMapper hardOrderMapper; @@ -262,6 +266,27 @@ public class HardOrderController { return R.ok(hardwareOrderService.page(page, wrapper)); } + @Operation(summary = "线上订餐统计", description = "按食堂统计线上订餐订单的菜品份数仅用 template_type=2 的线上模板,排除退款") + @PostMapping("/online-canteen-stats") + @PreAuthorize("@pms.hasPermission('hard_hardwareOrder_view')") + public R> onlineCanteenStats(@RequestBody HardOnlineCanteenStatsQueryDto query) { + if (query.getMchIds() == null || query.getMchIds().isEmpty()) { + query.setMchIds(null); + } + List mchDtoIds = query.getMchIds(); + if (ObjectUtil.isNotEmpty(mchDtoIds) && mchDtoIds.size() == 1) { + Long mchId = mchDtoIds.get(0); + List mchList = mchService.getByParentId(mchId).getData(); + if (ObjectUtil.isNotEmpty(mchList)) { + List mchIds = mchList.stream().map(MchManageVo::getId).toList(); + mchDtoIds = new java.util.ArrayList<>(List.of(mchId)); + mchDtoIds.addAll(mchIds); + query.setMchIds(mchDtoIds); + } + } + return R.ok(hardOnlineCanteenStatsService.stats(query)); + } + @Operation(summary = "分页复杂查询", description = "分页复杂查询") @PostMapping("/page-join") @PreAuthorize("@pms.hasPermission('hard_hardwareOrder_view')") diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOnlineCanteenStatsService.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOnlineCanteenStatsService.java new file mode 100644 index 000000000..8c17e5b4e --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOnlineCanteenStatsService.java @@ -0,0 +1,17 @@ +package com.bsd.pjcloud.hard.service; + +import com.bsd.pjcloud.hard.api.dto.order.HardOnlineCanteenStatsQueryDto; +import com.bsd.pjcloud.hard.api.vo.order.HardOnlineCanteenStatsVo; + +import java.util.List; + +/** + * 线上订餐统计服务(按食堂汇总:菜品、原料、营养) + */ +public interface HardOnlineCanteenStatsService { + + /** + * 统计各食堂线上订餐数据:订单数、菜品份数、原料用量、营养元素(排除退款) + */ + List stats(HardOnlineCanteenStatsQueryDto query); +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOnlineCanteenStatsServiceImpl.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOnlineCanteenStatsServiceImpl.java new file mode 100644 index 000000000..b9f1f19bd --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOnlineCanteenStatsServiceImpl.java @@ -0,0 +1,217 @@ +package com.bsd.pjcloud.hard.service.impl.order; + +import cn.hutool.core.util.ObjectUtil; +import com.bsd.pjcloud.canteen.api.feign.RemoteCanteenProductionTemplateService; +import com.bsd.pjcloud.canteen.api.feign.RemoteOnlineCanteenSpuService; +import com.bsd.pjcloud.canteen.vo.app.CanteenOnlineSpuAppVO; +import com.bsd.pjcloud.canteen.vo.erp.ProductTemplateVO; +import com.bsd.pjcloud.canteen.vo.erp.ProductionTemplateDetailVO; +import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum; +import com.bsd.pjcloud.common.core.util.R; +import com.bsd.pjcloud.common.data.datascope.DataScope; +import com.bsd.pjcloud.common.data.datascope.DataScopeFuncEnum; +import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum; +import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum; +import com.bsd.pjcloud.hard.api.constant.refund.HardRefundStatusEnum; +import com.bsd.pjcloud.hard.api.dto.order.HardOnlineCanteenStatsQueryDto; +import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto; +import com.bsd.pjcloud.hard.api.entity.order.HardCarEntity; +import com.bsd.pjcloud.hard.api.vo.order.*; +import com.bsd.pjcloud.hard.service.HardOrderService; +import com.bsd.pjcloud.hard.service.HardOnlineCanteenStatsService; +import com.bsd.pjcloud.wallet.api.feign.RemoteMchService; +import com.bsd.pjcloud.wallet.api.vo.MchManageVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 线上订餐统计实现 + * 仅统计线上订餐订单,排除退款,按食堂汇总:菜品份数、原料用量、营养元素 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class HardOnlineCanteenStatsServiceImpl implements HardOnlineCanteenStatsService { + + private final HardOrderService hardOrderService; + private final RemoteOnlineCanteenSpuService onlineCanteenSpuService; + private final RemoteCanteenProductionTemplateService productionTemplateService; + private final RemoteMchService mchService; + + @Override + public List stats(HardOnlineCanteenStatsQueryDto query) { + HardOrderDto dto = buildQueryDto(query); + DataScope dataScope = DataScope.of().func(DataScopeFuncEnum.ALL); + dataScope.setScopeDeptName("merchant_dept_id"); + List ordersWithCar = hardOrderService.scopeList(dto, dataScope); + if (ObjectUtil.isEmpty(ordersWithCar)) { + return Collections.emptyList(); + } + + Set onlineSpuIds = new HashSet<>(); + Map> merchantItems = new HashMap<>(); + Map merchantNameMap = new HashMap<>(); + for (HardOrderVo o : ordersWithCar) { + if (ObjectUtil.isEmpty(o.getCarList())) continue; + Long mchId = o.getMerchantId(); + if (mchId == null) continue; + merchantNameMap.put(mchId, o.getMerchantName()); + for (HardCarVo car : o.getCarList()) { + if (car.getProductId() == null || car.getProductCount() == null || car.getProductCount() <= 0) continue; + onlineSpuIds.add(car.getProductId()); + merchantItems.computeIfAbsent(mchId, k -> new ArrayList<>()) + .add(new OrderItem(car.getProductId(), car.getProductCount())); + } + } + if (onlineSpuIds.isEmpty()) { + return buildResult(merchantNameMap, Collections.emptyMap(), Collections.emptyMap()); + } + + R> spuRes = onlineCanteenSpuService.getSpuListByIds(new ArrayList<>(onlineSpuIds)); + List onlineSpus = (spuRes != null && spuRes.getData() != null) ? spuRes.getData() : Collections.emptyList(); + Map onlineSpuToLinkSpu = onlineSpus.stream() + .filter(s -> s.getLinkSpuId() != null) + .collect(Collectors.toMap(CanteenOnlineSpuAppVO::getId, CanteenOnlineSpuAppVO::getLinkSpuId, (a, b) -> a)); + + // 模板查找:每日菜品用 linkSpuId,常驻菜品用 onlineSpuId + // 优先查 template_type=2 的线上模板;若无则回退查全部(兼容未设置类型的模板) + Set dishIdsForTemplate = new HashSet<>(onlineSpuToLinkSpu.values()); + onlineSpus.stream().filter(s -> s.getLinkSpuId() == null).forEach(s -> dishIdsForTemplate.add(s.getId())); + Map dishIdToTemplate = new HashMap<>(); + if (!dishIdsForTemplate.isEmpty()) { + List templates = fetchTemplatesWithFallback(new ArrayList<>(dishIdsForTemplate)); + for (ProductTemplateVO t : templates) { + if (t.getDishId() != null) { + dishIdToTemplate.put(t.getDishId(), t); + } + } + } + + Map> merchantMaterialMap = new HashMap<>(); + Map merchantNutritionMap = new HashMap<>(); + Map merchantCounts = new HashMap<>(); + + for (Map.Entry> e : merchantItems.entrySet()) { + Long mchId = e.getKey(); + merchantMaterialMap.put(mchId, new HashMap<>()); + merchantNutritionMap.put(mchId, new NutritionAccumulator()); + long orderCount = ordersWithCar.stream().filter(o -> Objects.equals(o.getMerchantId(), mchId)).count(); + long dishCount = 0; + for (OrderItem item : e.getValue()) { + Long templateKey = onlineSpuToLinkSpu.getOrDefault(item.productId, item.productId); + ProductTemplateVO template = dishIdToTemplate.get(templateKey); + if (template == null || ObjectUtil.isEmpty(template.getCanteenProductionTemplateDetailList())) continue; + double baseOutput = ObjectUtil.defaultIfNull(template.getBaseOutput(), 1.0); + if (baseOutput <= 0) baseOutput = 1.0; + double ratio = item.count / baseOutput; + dishCount += item.count; + + for (ProductionTemplateDetailVO d : template.getCanteenProductionTemplateDetailList()) { + double baseUsage = ObjectUtil.defaultIfNull(d.getBaseUsage(), 0.0); + double lossRate = ObjectUtil.defaultIfNull(d.getLossRate(), 0.0); + double usage = ratio * baseUsage * (1 + lossRate); + merchantMaterialMap.get(mchId).computeIfAbsent(d.getMaterialId(), k -> new MaterialAccumulator(d.getMaterialId(), d.getMaterialName(), d.getUnit())) + .add(usage); + if (d.getNutritionDesc() != null && !d.getNutritionDesc().isBlank()) { + merchantNutritionMap.get(mchId).addDesc(d.getMaterialName(), d.getNutritionDesc()); + } + } + } + merchantCounts.put(mchId, new long[]{orderCount, dishCount}); + } + + return buildResult(merchantNameMap, merchantMaterialMap, merchantNutritionMap, merchantCounts); + } + + /** 优先查线上模板(type=2),无则回退查全部,兼容未设置 templateType 的模板 */ + private List fetchTemplatesWithFallback(List dishIds) { + R> res = productionTemplateService.getDetailsByDishIdsForOnline(dishIds); + List list = (res != null && res.getData() != null) ? res.getData() : Collections.emptyList(); + if (!list.isEmpty()) return list; + R> fallback = productionTemplateService.getDetailsByDishIds(dishIds); + return (fallback != null && fallback.getData() != null) ? fallback.getData() : Collections.emptyList(); + } + + private HardOrderDto buildQueryDto(HardOnlineCanteenStatsQueryDto query) { + HardOrderDto dto = new HardOrderDto(); + dto.setOrderTypeCodes(List.of(HardOrderTypeEnum.RESERVE.getType())); + dto.setMchTypeCodes(List.of(MerchantTypeEnum.CANTEEN.getType())); + dto.setOrderStatusCodes(HardOrderStatusEnum.getPaySuccessCodes()); + dto.setRefundStatusCodes(List.of(HardRefundStatusEnum.NONE.getStatus(), HardRefundStatusEnum.APPLY.getStatus(), HardRefundStatusEnum.REJECT.getStatus())); + dto.setPayTimeList(query.getPayTimeList()); + dto.setMchIds(query.getMchIds()); + dto.setIsFindCarList(true); + return dto; + } + + private List buildResult(Map merchantNameMap, + Map> materialMap, + Map nutritionMap) { + return buildResult(merchantNameMap, materialMap, nutritionMap, new HashMap<>()); + } + + private List buildResult(Map merchantNameMap, + Map> materialMap, + Map nutritionMap, + Map countsMap) { + Set mchIds = new HashSet<>(merchantNameMap.keySet()); + mchIds.addAll(materialMap.keySet()); + mchIds.addAll(nutritionMap.keySet()); + mchIds.addAll(countsMap.keySet()); + List result = new ArrayList<>(); + for (Long mchId : mchIds) { + HardOnlineCanteenStatsVo vo = new HardOnlineCanteenStatsVo(); + vo.setMerchantId(mchId); + vo.setMerchantName(merchantNameMap.getOrDefault(mchId, "")); + long[] c = countsMap.getOrDefault(mchId, new long[]{0, 0}); + vo.setOrderCount(c[0]); + vo.setTotalDishCount(c[1]); + Map mat = materialMap.getOrDefault(mchId, Collections.emptyMap()); + vo.setMaterialUsages(mat.values().stream().map(MaterialAccumulator::toVo).collect(Collectors.toList())); + vo.setNutritionSummary(nutritionMap.getOrDefault(mchId, new NutritionAccumulator()).toVo()); + result.add(vo); + } + result.sort(Comparator.comparing(HardOnlineCanteenStatsVo::getTotalDishCount).reversed()); + return result; + } + + private record OrderItem(Long productId, int count) {} + + private static class MaterialAccumulator { + Long materialId; + String materialName; + String unit; + double usage; + + MaterialAccumulator(Long materialId, String materialName, String unit) { + this.materialId = materialId; + this.materialName = materialName; + this.unit = unit; + } + void add(double u) { usage += u; } + HardOnlineCanteenMaterialUsageVo toVo() { + HardOnlineCanteenMaterialUsageVo vo = new HardOnlineCanteenMaterialUsageVo(); + vo.setMaterialId(materialId); + vo.setMaterialName(materialName); + vo.setUnit(unit); + vo.setUsage(usage); + return vo; + } + } + + private static class NutritionAccumulator { + private final Set descSet = new LinkedHashSet<>(); + void addDesc(String materialName, String nutritionDesc) { + descSet.add(materialName + ":" + nutritionDesc); + } + HardOnlineCanteenNutritionVo toVo() { + HardOnlineCanteenNutritionVo vo = new HardOnlineCanteenNutritionVo(); + vo.setNutritionDesc(String.join(";", descSet)); + return vo; + } + } +} 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 3977e4698..c481a446a 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 @@ -97,6 +97,12 @@ and a.order_type = #{dto.orderType} + + and a.order_type in + + #{v} + + and a.hour_type = #{dto.hourType} @@ -195,6 +201,13 @@ and a.pay_time between #{dto.payTimeList[0]} and #{dto.payTimeList[1]} + + and (a.refund_status in + + #{v} + + or a.refund_status is null) +