diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/dto/canteenonline/CanteenOnlineSpuSaveItemDto.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/dto/canteenonline/CanteenOnlineSpuSaveItemDto.java index 4df5dcebd..c0ff5cb23 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/dto/canteenonline/CanteenOnlineSpuSaveItemDto.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/dto/canteenonline/CanteenOnlineSpuSaveItemDto.java @@ -37,9 +37,9 @@ public class CanteenOnlineSpuSaveItemDto { private Integer sort; /** - * 商品状态: 1 上架(开启) 0 下架(禁用) -1 回收 + * 商品状态: 0 上架(默认/开启) 1 下架(禁用) -1 回收 */ - @Schema(description="商品状态: 1 上架(开启) 0 下架(禁用) -1 回收") + @Schema(description="商品状态: 0 上架(默认/开启) 1 下架(禁用) -1 回收") private Integer status; /** diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenOnlineSpuEntity.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenOnlineSpuEntity.java index 725228f3f..18e9411d7 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenOnlineSpuEntity.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/entity/CanteenOnlineSpuEntity.java @@ -78,9 +78,9 @@ public class CanteenOnlineSpuEntity extends Model { private Integer sort; /** - * 商品状态: 1 上架(开启) 0 下架(禁用) -1 回收 + * 商品状态: 0 上架(默认/开启) 1 下架(禁用) -1 回收 */ - @Schema(description="商品状态: 1 上架(开启) 0 下架(禁用) -1 回收") + @Schema(description="商品状态: 0 上架(默认/开启) 1 下架(禁用) -1 回收") private Integer status; /** diff --git a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/APPOnlineSpuVO.java b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/APPOnlineSpuVO.java index 92926665d..7666994a6 100644 --- a/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/APPOnlineSpuVO.java +++ b/pjcloud-canteen/pjcloud-canteen-api/src/main/java/com/bsd/pjcloud/canteen/vo/APPOnlineSpuVO.java @@ -96,6 +96,18 @@ public class APPOnlineSpuVO { @Schema(description="库存") private Integer stock; + /** + * 商品状态: 0 上架(默认) 1 下架 + */ + @Schema(description = "商品状态: 0 上架 1 下架") + private Integer status; + + /** + * 是否售罄(库存为空或≤0) + */ + @Schema(description = "是否售罄") + private Boolean soldOut; + /** * 商品销量 */ 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 ba6f67a2b..4a580d15c 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 @@ -6,6 +6,7 @@ import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.bsd.pjcloud.canteen.dto.CanteenOnlineSpuShelfReqDTO; import com.bsd.pjcloud.canteen.dto.CanteenOnlineSpuUpdateStockReqDTO; import com.bsd.pjcloud.canteen.dto.canteenonline.CanteenOnlineSpuSaveDto; import com.bsd.pjcloud.canteen.vo.APPOnlineSpuVO; @@ -27,6 +28,7 @@ import org.springdoc.core.annotations.ParameterObject; import org.springframework.http.HttpHeaders; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -207,15 +209,26 @@ public class CanteenOnlineSpuController { /** * 获取菜品列表 * - * @param categoryId 分类编号,不传默认查询全部 - * @return + * @param categoryId 分类编号,不传默认查询全部 + * @param minPrice 最低价(分),不传不限 + * @param maxPrice 最高价(分),不传不限 + * @param status 上架状态:0 上架 1 下架,不传不限 + * @param stockFilter in_stock 仅非售罄,sold_out 仅售罄,不传不限 + * @param priceOrder 按价格排序:asc 升序 desc 降序,不传则按 sort、id */ @GetMapping("/app/getCanteenSpuList") - @Operation(summary = "获取在线点餐的菜品列表", description = "1.通过分类id,可以不填,默认查全部,2.商户id,必传") - public R> getCanteenSpuList(@RequestParam(value = "categoryId", required = false) String categoryId, - @RequestParam(value = "merchantId") String merchantId, - @RequestParam(value = "time",required = false)String time) { - return canteenOnlineSpuService.getCanteenOnlineSpuList(categoryId, merchantId,time); + @Operation(summary = "获取在线点餐的菜品列表", description = "商户 id 必传;支持价格区间、上架状态、是否售罄筛选及按价格排序;返回含 status、soldOut") + public R> getCanteenSpuList( + @RequestParam(value = "categoryId", required = false) @Parameter(description = "分类 id,可选") String categoryId, + @RequestParam(value = "merchantId") @Parameter(description = "商户 id,必填") String merchantId, + @RequestParam(value = "time", required = false) @Parameter(description = "日期 yyyy-MM-dd,默认当天") String time, + @RequestParam(value = "minPrice", required = false) @Parameter(description = "最低价(分)") Integer minPrice, + @RequestParam(value = "maxPrice", required = false) @Parameter(description = "最高价(分)") Integer maxPrice, + @RequestParam(value = "status", required = false) @Parameter(description = "0 上架 1 下架") Integer status, + @RequestParam(value = "stockFilter", required = false) @Parameter(description = "in_stock | sold_out") String stockFilter, + @RequestParam(value = "priceOrder", required = false) @Parameter(description = "asc | desc") String priceOrder) { + return canteenOnlineSpuService.getCanteenOnlineSpuList(categoryId, merchantId, time, + minPrice, maxPrice, status, stockFilter, priceOrder); } @@ -224,6 +237,10 @@ public class CanteenOnlineSpuController { public R getCanteenSpuDetails(@RequestParam(value = "id") Long id) { CanteenOnlineSpuEntity canteenOnlineSpuEntity = canteenOnlineSpuService.getById(id); APPOnlineSpuVO bean = BeanUtils.toBean(canteenOnlineSpuEntity, APPOnlineSpuVO.class); + if (bean != null && canteenOnlineSpuEntity != null) { + Integer st = canteenOnlineSpuEntity.getStock(); + bean.setSoldOut(st == null || st <= 0); + } return R.ok(bean); } @@ -243,13 +260,44 @@ public class CanteenOnlineSpuController { } + /** + * 下单/支付等场景扣减库存,会与销量 sales_count 联动,请勿用于商家手工改库存。 + */ @PostMapping("/app/updateSkuStock") - @SysLog("更新菜品库存") + @SysLog("更新菜品库存(订单联动销量)") @Transactional public R updateSkuStock(@RequestBody CanteenOnlineSpuUpdateStockReqDTO canteenOnlineSpuUpdateStockReqDTO) { return canteenOnlineSpuService.updateOnlineSpuSkuStock(canteenOnlineSpuUpdateStockReqDTO); } + /** + * 商家端手工增减库存(只更新 stock,不修改销量);仅允许操作当前登录单位对应食堂商户下的 SPU。 + */ + @PostMapping("/app/adjustStock") + @Operation(summary = "商家调整菜品库存", description = "正数增加、负数减少;不联动销量,与下单接口 /app/updateSkuStock 区分") + @SysLog("商家调整菜品库存") + @Transactional + public R adjustStockForMerchant(@RequestBody CanteenOnlineSpuUpdateStockReqDTO canteenOnlineSpuUpdateStockReqDTO) { + Long deptId = SecurityUtils.getUser().getDeptId(); + R resp = remoteMchService.getByDeptId(deptId, MerchantTypeEnum.CANTEEN); + if (resp == null || !resp.isOk() || resp.getData() == null) { + return R.failed(resp != null ? resp.getMsg() : "商户不存在"); + } + return canteenOnlineSpuService.adjustOnlineSpuStockManual(resp.getData().getId(), canteenOnlineSpuUpdateStockReqDTO); + } + + @PostMapping("/app/updateShelfStatus") + @Operation(summary = "商家上架/下架菜品", description = "status:0-上架(默认),1-下架;仅可操作当前单位对应食堂商户下的 SPU") + @SysLog("商家上架下架菜品") + @Transactional + public R updateShelfStatusForMerchant(@RequestBody CanteenOnlineSpuShelfReqDTO dto) { + Long deptId = SecurityUtils.getUser().getDeptId(); + R resp = remoteMchService.getByDeptId(deptId, MerchantTypeEnum.CANTEEN); + if (resp == null || !resp.isOk() || resp.getData() == null) { + return R.failed(resp != null ? resp.getMsg() : "商户不存在"); + } + return canteenOnlineSpuService.updateOnlineSpuShelfStatus(resp.getData().getId(), dto); + } /** * 通过ids查询菜品spu diff --git a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/mapper/CanteenOnlineSpuMapper.java b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/mapper/CanteenOnlineSpuMapper.java index da1650ca2..6257d0e3a 100644 --- a/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/mapper/CanteenOnlineSpuMapper.java +++ b/pjcloud-canteen/pjcloud-canteen-biz/src/main/java/com/bsd/pjcloud/canteen/mapper/CanteenOnlineSpuMapper.java @@ -33,4 +33,21 @@ public interface CanteenOnlineSpuMapper extends PjcloudBaseMapper updateWrapper = new LambdaUpdateWrapper() + .setSql(sql) + .eq(CanteenOnlineSpuEntity::getId, id); + return update(null, updateWrapper); + } } \ 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 1e0272dac..bc3f71b67 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 @@ -3,6 +3,7 @@ package com.bsd.pjcloud.canteen.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; +import com.bsd.pjcloud.canteen.dto.CanteenOnlineSpuShelfReqDTO; import com.bsd.pjcloud.canteen.dto.CanteenOnlineSpuUpdateStockReqDTO; import com.bsd.pjcloud.canteen.dto.canteenonline.CanteenOnlineSpuSaveDto; import com.bsd.pjcloud.canteen.entity.CanteenOnlineSpuEntity; @@ -21,13 +22,20 @@ public interface CanteenOnlineSpuService extends IService> getCanteenOnlineSpuList(String categoryId, String merchantId,String time); + R> getCanteenOnlineSpuList(String categoryId, String merchantId, String time, + Integer minPrice, Integer maxPrice, Integer status, + String stockFilter, String priceOrder); /** @@ -37,6 +45,16 @@ public interface CanteenOnlineSpuService extends IService> getCanteenOnlineSpuList(String categoryId, String merchantId,String time) { + public R> getCanteenOnlineSpuList(String categoryId, String merchantId, String time, + Integer minPrice, Integer maxPrice, Integer status, + String stockFilter, String priceOrder) { + if (minPrice != null && maxPrice != null && minPrice > maxPrice) { + return R.failed("价格区间无效:minPrice 不能大于 maxPrice"); + } LambdaQueryWrapper canteenOnlineSpuEntityLambdaQueryWrapper = new LambdaQueryWrapper<>(); canteenOnlineSpuEntityLambdaQueryWrapper.eq(StringUtils.isNotEmpty(categoryId), CanteenOnlineSpuEntity::getCategoryId, categoryId); canteenOnlineSpuEntityLambdaQueryWrapper.eq(CanteenOnlineSpuEntity::getMerchantId, merchantId); + canteenOnlineSpuEntityLambdaQueryWrapper.ge(minPrice != null, CanteenOnlineSpuEntity::getPrice, minPrice); + canteenOnlineSpuEntityLambdaQueryWrapper.le(maxPrice != null, CanteenOnlineSpuEntity::getPrice, maxPrice); + canteenOnlineSpuEntityLambdaQueryWrapper.eq(status != null, CanteenOnlineSpuEntity::getStatus, status); + String sf = StrUtil.trimToEmpty(stockFilter); + if (StrUtil.equalsIgnoreCase(sf, "in_stock")) { + canteenOnlineSpuEntityLambdaQueryWrapper.gt(CanteenOnlineSpuEntity::getStock, 0); + } else if (StrUtil.equalsIgnoreCase(sf, "sold_out")) { + canteenOnlineSpuEntityLambdaQueryWrapper.and(w -> + w.le(CanteenOnlineSpuEntity::getStock, 0).or().isNull(CanteenOnlineSpuEntity::getStock)); + } + String po = StrUtil.trimToEmpty(priceOrder); + if (StrUtil.equalsIgnoreCase(po, "asc")) { + canteenOnlineSpuEntityLambdaQueryWrapper.orderByAsc(CanteenOnlineSpuEntity::getPrice) + .orderByAsc(CanteenOnlineSpuEntity::getSort).orderByDesc(CanteenOnlineSpuEntity::getId); + } else if (StrUtil.equalsIgnoreCase(po, "desc")) { + canteenOnlineSpuEntityLambdaQueryWrapper.orderByDesc(CanteenOnlineSpuEntity::getPrice) + .orderByAsc(CanteenOnlineSpuEntity::getSort).orderByDesc(CanteenOnlineSpuEntity::getId); + } else { + canteenOnlineSpuEntityLambdaQueryWrapper.orderByAsc(CanteenOnlineSpuEntity::getSort) + .orderByDesc(CanteenOnlineSpuEntity::getId); + } List canteenSpuEntities = baseMapper.selectList(canteenOnlineSpuEntityLambdaQueryWrapper); //根据商户查询当前日期的每日菜谱,查询每日菜谱上架的菜的id,然后在从在线订餐的列表筛选出今天有上新的数据 @@ -77,20 +105,22 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl bean = BeanUtils.toBean(finallyCanteenSpuEntities, APPOnlineSpuVO.class); + for (int i = 0; i < bean.size(); i++) { + Integer st = finallyCanteenSpuEntities.get(i).getStock(); + bean.get(i).setSoldOut(st == null || st <= 0); + } return R.ok(bean); } @Override public R updateOnlineSpuSkuStock(CanteenOnlineSpuUpdateStockReqDTO canteenOnlineSpuUpdateStockReqDTO) { - // 更新 SKU 库存 + // 下单等场景:库存与销量联动(incrCount<0 视为售出) for (CanteenOnlineSpuUpdateStockReqDTO.Item v : canteenOnlineSpuUpdateStockReqDTO.getItems()) { - // 查询当前库存 CanteenOnlineSpuEntity spu = baseMapper.selectById(v.getId()); if (spu == null) { - return R.failed(spu.getName() + "商品不存在"); + return R.failed("商品不存在"); } - // 检查库存是否足够 if (v.getIncrCount() < 0 && Math.abs(v.getIncrCount()) > spu.getStock()) { return R.failed(spu.getName() + "库存不足,无法完成操作"); } @@ -99,6 +129,45 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl spu.getStock()) { + return R.failed(StrUtil.blankToDefault(spu.getName(), "商品") + "库存不足,无法完成操作"); + } + baseMapper.adjustStockOnly(v.getId(), v.getIncrCount()); + } + return R.ok(); + } + + @Override + public R updateOnlineSpuShelfStatus(Long merchantId, CanteenOnlineSpuShelfReqDTO dto) { + Integer status = dto.getStatus(); + if (status == null || (status != 0 && status != 1)) { + return R.failed("状态非法,仅支持 0-上架、1-下架"); + } + CanteenOnlineSpuEntity spu = baseMapper.selectById(dto.getId()); + if (spu == null) { + return R.failed("商品不存在"); + } + if (!Objects.equals(spu.getMerchantId(), merchantId)) { + return R.failed("无权操作该商品"); + } + LambdaUpdateWrapper uw = new LambdaUpdateWrapper() + .eq(CanteenOnlineSpuEntity::getId, dto.getId()) + .eq(CanteenOnlineSpuEntity::getMerchantId, merchantId) + .set(CanteenOnlineSpuEntity::getStatus, status); + baseMapper.update(null, uw); + return R.ok(); + } + @Override @Transactional public Object saveCanteenSpuBatch(CanteenOnlineSpuSaveDto canteenOnlineSpuSaveDto) { diff --git a/pjcloud-upms/pjcloud-upms-api/src/main/java/com/bsd/pjcloud/admin/api/entity/SysDept.java b/pjcloud-upms/pjcloud-upms-api/src/main/java/com/bsd/pjcloud/admin/api/entity/SysDept.java index bb2d330d0..19df0406a 100644 --- a/pjcloud-upms/pjcloud-upms-api/src/main/java/com/bsd/pjcloud/admin/api/entity/SysDept.java +++ b/pjcloud-upms/pjcloud-upms-api/src/main/java/com/bsd/pjcloud/admin/api/entity/SysDept.java @@ -77,6 +77,13 @@ public class SysDept extends Model { @Schema(description = "是否同步到正元") private String isSyncZy; + /** + * 是否单位:0-否 1-是(用于订餐等业务区分“单位/部门”) + */ + @Schema(description = "是否单位:0-否 1-是") + @TableField("is_unit") + private Integer isUnit; + /** * 创建人 */ diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/resources/mapper/SysDeptMapper.xml b/pjcloud-upms/pjcloud-upms-biz/src/main/resources/mapper/SysDeptMapper.xml index 26f0f5838..676a923b5 100644 --- a/pjcloud-upms/pjcloud-upms-biz/src/main/resources/mapper/SysDeptMapper.xml +++ b/pjcloud-upms/pjcloud-upms-biz/src/main/resources/mapper/SysDeptMapper.xml @@ -25,6 +25,7 @@ + @@ -39,6 +40,7 @@ a.hard_group_id, a.sort_order, a.is_sync_zy, + a.is_unit, a.create_by, a.update_by, a.create_time,