共富接口修改

This commit is contained in:
zjf committed 2025-10-22 18:03:12 +08:00
1 parent 8647444e10
commit 0db2942043
12 files changed
+264 -244

No files matched your search

@@ -56,14 +56,12 @@ public interface RemoteMallProductService {
/**
* 购物车校验库存
*
* @param productId 商品ID(多SKU模式传SKU ID,单SPU模式传SPU ID)
* @param productType 商品类型(1=SKU, 2=SPU)
* @param skuId SKU ID
* @param incrCount 扣减数量(正数或负数)
* @return 库存是否充足
*/
@GetMapping("/mallProduct/checkStock")
R<Boolean> checkStock(@RequestParam("productId") Long productId,
@RequestParam("productType") Integer productType,
R<Boolean> checkStock(@RequestParam("skuId") Long skuId,
@RequestParam("incrCount") Double incrCount);
/**
@@ -129,5 +127,14 @@ public interface RemoteMallProductService {
*/
@GetMapping("/mallProduct/listByIds")
R<List<MallProductEntity>> getListByIds(@RequestParam("ids") List<Long> ids);
/**
* 根据SKU ID列表批量查询SKU和SPU信息
*
* @param skuIds SKU ID列表
* @return SKU和SPU详情列表
*/
@GetMapping("/mallProduct/getSkusWithSpu")
R<List<MallProductDetailAppVo>> getSkusWithSpuBySkuIds(@RequestParam("skuIds") List<Long> skuIds);
}
@@ -27,16 +27,13 @@ public class MallProductStockChangeDTO {
@Schema(description = "库存变更明细")
public static class Item {
@NotNull(message = "商品ID不能为空(SPU或SKU ID)")
@Schema(description = "商品ID(多SKU模式传SKU ID,单SPU模式传SPU ID)")
@NotNull(message = "SKU ID不能为空")
@Schema(description = "SKU ID")
private Long id;
@NotNull(message = "库存变化数量不能为空")
@Schema(description = "库存变化数量(正数增加,负数扣减)")
private Double incrCount;
@Schema(description = "商品类型(1=SKU, 2=SPU)")
private Integer productType;
}
}
@@ -64,18 +64,6 @@ public class MallProductDetailAppVo {
@Schema(description = "轮播图")
private String carouselImages;
/**
* 定价方式(1多SKU 2单价SPU)
*/
@Schema(description = "定价方式")
private Integer priceType;
/**
* SPU售价(单位:分)
*/
@Schema(description = "SPU售价(单位:分)")
private Integer spuPrice;
/**
* 划线价(单位:分)
*/
@@ -43,12 +43,6 @@ public class MallProductListAppVo {
@Schema(description = "副标题")
private String subTitle;
/**
* 品牌
*/
@Schema(description = "品牌")
private String brand;
/**
* 主图
*/
@@ -61,18 +55,6 @@ public class MallProductListAppVo {
@Schema(description = "轮播图")
private String carouselImages;
/**
* 定价方式(1多SKU 2单价SPU)
*/
@Schema(description = "定价方式")
private Integer priceType;
/**
* SPU售价(单位:分)
*/
@Schema(description = "SPU售价(单位:分)")
private Integer spuPrice;
/**
* 划线价(单位:分)
*/
@@ -98,9 +80,9 @@ public class MallProductListAppVo {
private String status;
/**
* 最低价格(从SKU中计算,单位:分)
* 零售价(从SKU中取最低价,单位:分)
*/
@Schema(description = "最低价格(单位:分)")
private Integer minPrice;
@Schema(description = "零售价")
private Integer retailPrice;
}
@@ -214,8 +214,9 @@ public class MallProductController {
/**
* 批量扣减/增加库存(正数增加,负数扣减)
* 统一通过SKU ID进行库存变更
*/
@Operation(summary = "批量扣减/增加库存", description = "批量扣减/增加库存")
@Operation(summary = "批量扣减/增加库存", description = "批量扣减/增加库存(基于SKU ID)")
@PostMapping("/deductStock")
public R<Boolean> deductStock(@Valid @RequestBody MallProductStockChangeDTO changes) {
try {
@@ -224,43 +225,22 @@ public class MallProductController {
}
for (MallProductStockChangeDTO.Item item : changes.getItems()) {
if (item.getProductType() == null) {
return R.failed("商品类型不能为空");
// 统一使用SKU ID进行库存变更
MallProductSkuEntity sku = mallProductSkuService.getById(item.getId());
if (sku == null) {
return R.failed("SKU不存在:" + item.getId());
}
if (item.getProductType() == 1) {
// SKU 模式:更新 SKU 库存
MallProductSkuEntity sku = mallProductSkuService.getById(item.getId());
if (sku == null) {
return R.failed("SKU不存在:" + item.getId());
}
Double newStock = (sku.getStock() != null ? sku.getStock() : 0D) + item.getIncrCount();
if (newStock < 0) {
return R.failed("SKU库存不足:" + sku.getSkuName());
}
sku.setStock(newStock);
mallProductSkuService.updateById(sku);
// 更新 SPU 总库存
updateSpuTotalStock(sku.getProductId());
} else if (item.getProductType() == 2) {
// SPU 模式:直接更新 SPU 总库存
MallProductEntity product = mallProductService.getById(item.getId());
if (product == null) {
return R.failed("商品不存在:" + item.getId());
}
Double newStock = (product.getTotalStock() != null ? product.getTotalStock() : 0D) + item.getIncrCount();
if (newStock < 0) {
return R.failed("商品库存不足:" + product.getTitle());
}
product.setTotalStock(newStock);
mallProductService.updateById(product);
Double newStock = (sku.getStock() != null ? sku.getStock() : 0D) + item.getIncrCount();
if (newStock < 0) {
return R.failed("SKU库存不足:" + sku.getSkuName());
}
sku.setStock(newStock);
mallProductSkuService.updateById(sku);
// 更新 SPU 总库存
updateSpuTotalStock(sku.getProductId());
}
return R.ok(true);
@@ -270,36 +250,20 @@ public class MallProductController {
}
/**
* 购物车校验库存
* 购物车校验库存(基于SKU ID)
*/
@Operation(summary = "购物车校验库存", description = "购物车校验库存")
@Operation(summary = "购物车校验库存", description = "购物车校验库存(基于SKU ID)")
@GetMapping("/checkStock")
public R<Boolean> checkStock(@RequestParam("productId") Long productId,
@RequestParam("productType") Integer productType,
public R<Boolean> checkStock(@RequestParam("skuId") Long skuId,
@RequestParam("incrCount") Double incrCount) {
try {
if (productType == 1) {
// SKU 模式
MallProductSkuEntity sku = mallProductSkuService.getById(productId);
if (sku == null) {
return R.ok(false);
}
Double currentStock = sku.getStock() != null ? sku.getStock() : 0D;
return R.ok(currentStock + incrCount >= 0);
} else if (productType == 2) {
// SPU 模式
MallProductEntity product = mallProductService.getById(productId);
if (product == null) {
return R.ok(false);
}
Double currentStock = product.getTotalStock() != null ? product.getTotalStock() : 0D;
return R.ok(currentStock + incrCount >= 0);
MallProductSkuEntity sku = mallProductSkuService.getById(skuId);
if (sku == null) {
return R.ok(false);
}
return R.failed("无效的商品类型");
Double currentStock = sku.getStock() != null ? sku.getStock() : 0D;
return R.ok(currentStock + incrCount >= 0);
} catch (Exception e) {
return R.failed("校验库存失败:" + e.getMessage());
}
@@ -363,6 +327,75 @@ public class MallProductController {
return R.ok(mallProductService.listByIds(ids));
}
/**
* 根据SKU ID列表批量查询SKU和SPU信息
*/
@Operation(summary = "根据SKU ID列表批量查询SKU和SPU信息", description = "根据SKU ID列表批量查询SKU和SPU信息(包含完整SPU详情)")
@GetMapping("/getSkusWithSpu")
public R<List<MallProductDetailAppVo>> getSkusWithSpuBySkuIds(@RequestParam("skuIds") List<Long> skuIds) {
try {
if (CollUtil.isEmpty(skuIds)) {
return R.ok(new java.util.ArrayList<>());
}
// 1. 查询所有SKU
List<MallProductSkuEntity> skuList = mallProductSkuService.listByIds(skuIds);
if (CollUtil.isEmpty(skuList)) {
return R.ok(new java.util.ArrayList<>());
}
// 2. 获取所有关联的商品ID
List<Long> productIds = skuList.stream()
.map(MallProductSkuEntity::getProductId)
.distinct()
.collect(java.util.stream.Collectors.toList());
// 3. 查询所有商品
List<MallProductEntity> products = mallProductService.listByIds(productIds);
// 4. 按商品ID分组SKU
java.util.Map<Long, List<MallProductSkuEntity>> skuMap = skuList.stream()
.collect(java.util.stream.Collectors.groupingBy(MallProductSkuEntity::getProductId));
// 5. 组装结果(每个商品只包含查询的SKU,不是全部SKU)
List<MallProductDetailAppVo> voList = products.stream()
.map(product -> {
MallProductDetailAppVo vo = new MallProductDetailAppVo();
vo.setId(product.getId());
vo.setMerchantId(product.getMerchantId());
vo.setCategoryId(product.getCategoryId());
vo.setTitle(product.getTitle());
vo.setSubTitle(product.getSubTitle());
vo.setBrand(product.getBrand());
vo.setCoverImage(product.getCoverImage());
vo.setCarouselImages(product.getCarouselImages());
vo.setOriginalPrice(product.getOriginalPrice());
vo.setTotalStock(product.getTotalStock());
vo.setProductNature(product.getProductNature());
vo.setStatus(product.getStatus());
vo.setSaleStartTime(product.getSaleStartTime());
vo.setSaleEndTime(product.getSaleEndTime());
vo.setDescription(product.getDescription());
// 只包含请求的SKU
List<MallProductSkuEntity> productSkus = skuMap.get(product.getId());
if (CollUtil.isNotEmpty(productSkus)) {
List<MallProductSkuAppVo> skuVoList = productSkus.stream()
.map(this::convertToSkuVo)
.collect(java.util.stream.Collectors.toList());
vo.setSkuList(skuVoList);
}
return vo;
})
.collect(java.util.stream.Collectors.toList());
return R.ok(voList);
} catch (Exception e) {
return R.failed("根据SKU ID查询商品失败:" + e.getMessage());
}
}
// ==================== 私有辅助方法 ====================
/**
@@ -394,30 +427,22 @@ public class MallProductController {
vo.setCategoryId(product.getCategoryId());
vo.setTitle(product.getTitle());
vo.setSubTitle(product.getSubTitle());
vo.setBrand(product.getBrand());
vo.setCoverImage(product.getCoverImage());
vo.setCarouselImages(product.getCarouselImages());
vo.setPriceType(product.getPriceType());
vo.setSpuPrice(product.getSpuPrice());
vo.setOriginalPrice(product.getOriginalPrice());
vo.setTotalStock(product.getTotalStock());
vo.setProductNature(product.getProductNature());
vo.setStatus(product.getStatus());
// 如果是多SKU模式,计算最低价格
if (product.getPriceType() != null && product.getPriceType() == 1) {
List<MallProductSkuEntity> skuList = mallProductSkuService.list(
Wrappers.<MallProductSkuEntity>lambdaQuery()
.eq(MallProductSkuEntity::getProductId, product.getId())
.orderByAsc(MallProductSkuEntity::getPrice)
);
if (CollUtil.isNotEmpty(skuList)) {
vo.setMinPrice(skuList.get(0).getPrice());
}
} else {
// 单SPU模式,最低价格就是SPU价格
vo.setMinPrice(product.getSpuPrice());
// 查询SKU列表,获取零售价(取最低价格的SKU)
List<MallProductSkuEntity> skuList = mallProductSkuService.list(
Wrappers.<MallProductSkuEntity>lambdaQuery()
.eq(MallProductSkuEntity::getProductId, product.getId())
.orderByAsc(MallProductSkuEntity::getPrice)
);
if (CollUtil.isNotEmpty(skuList)) {
vo.setRetailPrice(skuList.get(0).getPrice());
}
return vo;
@@ -436,8 +461,6 @@ public class MallProductController {
vo.setBrand(product.getBrand());
vo.setCoverImage(product.getCoverImage());
vo.setCarouselImages(product.getCarouselImages());
vo.setPriceType(product.getPriceType());
vo.setSpuPrice(product.getSpuPrice());
vo.setOriginalPrice(product.getOriginalPrice());
vo.setTotalStock(product.getTotalStock());
vo.setProductNature(product.getProductNature());
@@ -446,18 +469,16 @@ public class MallProductController {
vo.setSaleEndTime(product.getSaleEndTime());
vo.setDescription(product.getDescription());
// 如果是多SKU模式,查询SKU列表
if (product.getPriceType() != null && product.getPriceType() == 1) {
List<MallProductSkuEntity> skuList = mallProductSkuService.list(
Wrappers.<MallProductSkuEntity>lambdaQuery()
.eq(MallProductSkuEntity::getProductId, product.getId())
);
// 查询SKU列表
List<MallProductSkuEntity> skuList = mallProductSkuService.list(
Wrappers.<MallProductSkuEntity>lambdaQuery()
.eq(MallProductSkuEntity::getProductId, product.getId())
);
List<MallProductSkuAppVo> skuVoList = skuList.stream()
.map(this::convertToSkuVo)
.collect(java.util.stream.Collectors.toList());
vo.setSkuList(skuVoList);
}
List<MallProductSkuAppVo> skuVoList = skuList.stream()
.map(this::convertToSkuVo)
.collect(java.util.stream.Collectors.toList());
vo.setSkuList(skuVoList);
return vo;
}
@@ -12,6 +12,7 @@ import com.bsd.pjcloud.common.excel.annotation.RequestExcel;
import com.bsd.pjcloud.common.idempotent.annotation.Idempotent;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.supermarket.dto.StockWarnQueryDTO;
import com.bsd.pjcloud.supermarket.dto.SupermarketSpuAppQueryDTO;
import com.bsd.pjcloud.supermarket.dto.SupermarketSpuQueryDTO;
import com.bsd.pjcloud.supermarket.dto.SupermarketSpuUpdateStockByCodeReqDTO;
@@ -222,17 +223,34 @@ public class SmErpSpuController {
}
/**
* 分页查询
* 分页查询库存预警
* @param page 分页对象
* @param supermarketSpu 商品spu
* @param queryDTO 查询条件
* @return
*/
@Operation(summary = "分页查询库存预警" , description = "分页查询库存预警" )
@GetMapping("/warnStock/page" )
@PreAuthorize("@pms.hasPermission('supermarket_supermarketSpu_view')" )
public R getWarnStockPage(@ParameterObject Page page, @ParameterObject SmErpSpuEntity supermarketSpu) {
public R getWarnStockPage(@ParameterObject Page page, @ParameterObject StockWarnQueryDTO queryDTO) {
// 调试日志:打印查询参数
System.out.println("========== 库存预警查询参数 ==========");
System.out.println("分页参数 - current: " + page.getCurrent() + ", size: " + page.getSize());
if (queryDTO != null) {
System.out.println("warnType: " + queryDTO.getWarnType() + " (类型: " + (queryDTO.getWarnType() != null ? queryDTO.getWarnType().getClass().getName() : "null") + ")");
System.out.println("warnType.equals(\"1\"): " + (queryDTO.getWarnType() != null && queryDTO.getWarnType().equals("1")));
System.out.println("warnType == \"1\": " + (queryDTO.getWarnType() != null && queryDTO.getWarnType() == "1"));
System.out.println("barcode: " + queryDTO.getBarcode());
System.out.println("productCode: " + queryDTO.getProductCode());
System.out.println("productName: " + queryDTO.getProductName());
System.out.println("categoryId: " + queryDTO.getCategoryId());
} else {
System.out.println("queryDTO is NULL!");
}
System.out.println("======================================");
IPage iPage = smErpStockService.selectWarnStockWithSpu(page, supermarketSpu);
IPage iPage = smErpStockService.selectWarnStockWithSpu(page, queryDTO);
System.out.println("查询结果数量: " + iPage.getRecords().size() + " / 总数: " + iPage.getTotal());
return R.ok(iPage);
@@ -72,19 +72,6 @@ public class MallProductCreateDTO {
@Schema(description = "SPU轮播图URL(逗号分隔,按顺序)")
private String carouselImages;
/**
* 定价方式(1多SKU 2单价SPU)
*/
@NotNull(message = "定价方式不能为空")
@Schema(description = "定价方式(1多SKU 2单价SPU)")
private Integer priceType;
/**
* SPU售价(当price_type=2有效)
*/
@Schema(description = "SPU售价(当price_type=2有效)")
private Integer spuPrice;
/**
* 划线价
*/
@@ -92,13 +79,13 @@ public class MallProductCreateDTO {
private Integer originalPrice;
/**
* 总库存(冗余)
* 总库存(冗余,由SKU汇总计算)
*/
@Schema(description = "总库存(冗余)")
@Schema(description = "总库存(冗余,由SKU汇总计算)")
private Double totalStock;
/**
* 计量单位
* 商品性质
*/
@Schema(description = "商品性质")
private String productNature;
@@ -130,7 +117,7 @@ public class MallProductCreateDTO {
/**
* SKU列表(当priceType=1时必填)
* SKU列表(可选,单个商品一条SKU,多规格商品多条SKU)
*/
@Valid
@Schema(description = "SKU列表")
@@ -3,11 +3,10 @@ package com.bsd.pjcloud.supermarket.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.UpdateStockDTO;
import com.bsd.pjcloud.supermarket.entity.SmErpSpuEntity;
import com.bsd.pjcloud.supermarket.dto.StockWarnQueryDTO;
import com.bsd.pjcloud.supermarket.entity.SmErpStockEntity;
import com.bsd.pjcloud.supermarket.vo.stockwarn.StockWarnVO;
import com.github.houbb.heaven.annotation.reflect.Param;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@@ -16,7 +15,7 @@ import java.util.List;
public interface SmErpStockMapper extends PjcloudBaseMapper<SmErpStockEntity> {
IPage<StockWarnVO> selectWarnStockWithSpu(Page<SmErpStockEntity> page, @Param("param") SmErpSpuEntity param);
IPage<StockWarnVO> selectWarnStockWithSpu(Page<SmErpStockEntity> page, @Param("query") StockWarnQueryDTO query);
}
@@ -3,8 +3,8 @@ package com.bsd.pjcloud.supermarket.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.supermarket.dto.StockWarnQueryDTO;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.UpdateStockDTO;
import com.bsd.pjcloud.supermarket.entity.SmErpSpuEntity;
import com.bsd.pjcloud.supermarket.entity.SmErpStockEntity;
import com.bsd.pjcloud.supermarket.vo.stockwarn.StockWarnVO;
import com.github.houbb.heaven.annotation.reflect.Param;
@@ -15,7 +15,7 @@ public interface SmErpStockService extends IService<SmErpStockEntity> {
IPage<StockWarnVO> selectWarnStockWithSpu(Page<SmErpStockEntity> page,SmErpSpuEntity param);
IPage<StockWarnVO> selectWarnStockWithSpu(Page<SmErpStockEntity> page, StockWarnQueryDTO queryDTO);
/**
@@ -38,6 +38,7 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
public boolean createProductWithSkus(MallProductCreateDTO productCreateDTO) {
// 业务验证
validateProductData(productCreateDTO);
// 1. 创建SPU
MallProductEntity product = new MallProductEntity();
product.setMerchantId(productCreateDTO.getMerchantId());
@@ -47,8 +48,6 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
product.setBrand(productCreateDTO.getBrand());
product.setCoverImage(productCreateDTO.getCoverImage());
product.setCarouselImages(productCreateDTO.getCarouselImages());
product.setPriceType(productCreateDTO.getPriceType());
product.setSpuPrice(productCreateDTO.getSpuPrice());
product.setOriginalPrice(productCreateDTO.getOriginalPrice());
product.setProductNature(productCreateDTO.getProductNature());
product.setStatus(productCreateDTO.getStatus());
@@ -62,9 +61,8 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
throw new RuntimeException("保存商品SPU失败");
}
// 3. 处理SKU
if (productCreateDTO.getPriceType() == 1 && CollUtil.isNotEmpty(productCreateDTO.getSkuList())) {
// 多SKU模式,保存SKU列表
// 3. 处理SKU(如果有)
if (CollUtil.isNotEmpty(productCreateDTO.getSkuList())) {
List<MallProductSkuEntity> skuList = productCreateDTO.getSkuList().stream()
.map(skuDTO -> {
MallProductSkuEntity sku = new MallProductSkuEntity();
@@ -93,21 +91,9 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
.sum();
product.setTotalStock(totalStock);
this.updateById(product);
} else if (productCreateDTO.getPriceType() == 2) {
// 单价SPU模式,使用前端传入的totalStock
Double totalStock = productCreateDTO.getTotalStock();
if (totalStock == null) {
totalStock = 0D; // 如果没有传入,默认为0
}
product.setTotalStock(totalStock);
this.updateById(product);
} else {
// 没有SKU信息,使用前端传入的totalStock或默认为0
Double totalStock = productCreateDTO.getTotalStock();
if (totalStock == null) {
totalStock = 0D;
}
product.setTotalStock(totalStock);
// 没有SKU,总库存为0
product.setTotalStock(0D);
this.updateById(product);
}
@@ -134,8 +120,6 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
product.setBrand(productCreateDTO.getBrand());
product.setCoverImage(productCreateDTO.getCoverImage());
product.setCarouselImages(productCreateDTO.getCarouselImages());
product.setPriceType(productCreateDTO.getPriceType());
product.setSpuPrice(productCreateDTO.getSpuPrice());
product.setOriginalPrice(productCreateDTO.getOriginalPrice());
product.setProductNature(productCreateDTO.getProductNature());
product.setStatus(productCreateDTO.getStatus());
@@ -149,9 +133,8 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
throw new RuntimeException("更新商品SPU失败");
}
// 3. 处理SKU
if (productCreateDTO.getPriceType() == 1 && CollUtil.isNotEmpty(productCreateDTO.getSkuList())) {
// 多SKU模式,精确处理SKU的增删改
// 3. 处理SKU(精确处理SKU的增删改)
if (CollUtil.isNotEmpty(productCreateDTO.getSkuList())) {
updateSkusForProduct(product.getId(), productCreateDTO.getSkuList());
// 计算总库存
@@ -165,17 +148,12 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
product.setTotalStock(totalStock);
this.updateById(product);
} else {
// 单价SPU模式或没有SKU信息,删除所有SKU
// 没有SKU信息,删除所有SKU
LambdaQueryWrapper<MallProductSkuEntity> deleteWrapper = Wrappers.lambdaQuery();
deleteWrapper.eq(MallProductSkuEntity::getProductId, product.getId());
mallProductSkuService.remove(deleteWrapper);
// 使用前端传入的totalStock
Double totalStock = productCreateDTO.getTotalStock();
if (totalStock == null) {
totalStock = 0D; // 如果没有传入,默认为0
}
product.setTotalStock(totalStock);
product.setTotalStock(0D);
this.updateById(product);
}
@@ -293,8 +271,6 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
dto.setBrand(product.getBrand());
dto.setCoverImage(product.getCoverImage());
dto.setCarouselImages(product.getCarouselImages());
dto.setPriceType(product.getPriceType());
dto.setSpuPrice(product.getSpuPrice());
dto.setOriginalPrice(product.getOriginalPrice());
dto.setTotalStock(product.getTotalStock());
dto.setProductNature(product.getProductNature());
@@ -304,29 +280,27 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
dto.setDescription(product.getDescription());
// 3. 获取SKU信息
if (product.getPriceType() == 1) {
LambdaQueryWrapper<MallProductSkuEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MallProductSkuEntity::getProductId, id);
List<MallProductSkuEntity> skuList = mallProductSkuService.list(wrapper);
List<MallProductSkuCreateDTO> skuDTOList = skuList.stream()
.map(sku -> {
MallProductSkuCreateDTO skuDTO = new MallProductSkuCreateDTO();
skuDTO.setSkuCode(sku.getSkuCode());
skuDTO.setSkuName(sku.getSkuName());
skuDTO.setPrice(sku.getPrice());
skuDTO.setCostPrice(sku.getCostPrice());
skuDTO.setStock(sku.getStock());
skuDTO.setBarcode(sku.getBarcode());
skuDTO.setWeightG(sku.getWeightG());
skuDTO.setVolumeCm3(sku.getVolumeCm3());
skuDTO.setStatus(sku.getStatus());
return skuDTO;
})
.collect(Collectors.toList());
dto.setSkuList(skuDTOList);
}
LambdaQueryWrapper<MallProductSkuEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MallProductSkuEntity::getProductId, id);
List<MallProductSkuEntity> skuList = mallProductSkuService.list(wrapper);
List<MallProductSkuCreateDTO> skuDTOList = skuList.stream()
.map(sku -> {
MallProductSkuCreateDTO skuDTO = new MallProductSkuCreateDTO();
skuDTO.setSkuCode(sku.getSkuCode());
skuDTO.setSkuName(sku.getSkuName());
skuDTO.setPrice(sku.getPrice());
skuDTO.setCostPrice(sku.getCostPrice());
skuDTO.setStock(sku.getStock());
skuDTO.setBarcode(sku.getBarcode());
skuDTO.setWeightG(sku.getWeightG());
skuDTO.setVolumeCm3(sku.getVolumeCm3());
skuDTO.setStatus(sku.getStatus());
return skuDTO;
})
.collect(Collectors.toList());
dto.setSkuList(skuDTOList);
return dto;
}
@@ -336,12 +310,8 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
* @param productCreateDTO 商品创建DTO
*/
private void validateProductData(MallProductCreateDTO productCreateDTO) {
// 多SKU模式验证
if (productCreateDTO.getPriceType() == 1) {
if (CollUtil.isEmpty(productCreateDTO.getSkuList())) {
throw new RuntimeException("多SKU模式下必须提供SKU列表");
}
// 如果有SKU,验证SKU数据
if (CollUtil.isNotEmpty(productCreateDTO.getSkuList())) {
// 验证SKU编码在当前请求中的唯一性
long distinctSkuCodes = productCreateDTO.getSkuList().stream()
.map(MallProductSkuCreateDTO::getSkuCode)
@@ -368,12 +338,5 @@ public class MallProductServiceImpl extends ServiceImpl<MallProductMapper, MallP
throw new RuntimeException("SKU编码已存在,请使用不同的编码");
}
}
// 单价SPU模式验证
if (productCreateDTO.getPriceType() == 2) {
if (productCreateDTO.getSpuPrice() == null || productCreateDTO.getSpuPrice() <= 0) {
throw new RuntimeException("单价SPU模式下必须设置有效的SPU价格");
}
}
}
}
@@ -4,9 +4,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.supermarket.dto.StockWarnQueryDTO;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.InventoryRecordSaveItemDTO;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.UpdateStockDTO;
import com.bsd.pjcloud.supermarket.entity.SmErpSpuEntity;
import com.bsd.pjcloud.supermarket.entity.SmErpStockEntity;
import com.bsd.pjcloud.supermarket.entity.SmErpUnitEntity;
import com.bsd.pjcloud.supermarket.mapper.SmErpSpuMapper;
@@ -39,8 +39,50 @@ public class SmErpStockServiceImpl extends ServiceImpl<SmErpStockMapper, SmErpSt
@Override
public IPage<StockWarnVO> selectWarnStockWithSpu(Page<SmErpStockEntity> page, SmErpSpuEntity param) {
return baseMapper.selectWarnStockWithSpu(page, param);
public IPage<StockWarnVO> selectWarnStockWithSpu(Page<SmErpStockEntity> page, StockWarnQueryDTO queryDTO) {
// 如果有 warnType 参数,需要特殊处理分页
if (queryDTO != null && queryDTO.getWarnType() != null && !queryDTO.getWarnType().isEmpty()) {
String targetWarnType = queryDTO.getWarnType();
// 创建一个临时的查询对象,不带 warnType(查询所有预警数据)
StockWarnQueryDTO tempQuery = new StockWarnQueryDTO();
tempQuery.setProductCode(queryDTO.getProductCode());
tempQuery.setBarcode(queryDTO.getBarcode());
tempQuery.setProductName(queryDTO.getProductName());
tempQuery.setCategoryId(queryDTO.getCategoryId());
tempQuery.setWarnType(null); // 设为 null,查询所有预警
// 查询所有预警数据(不分页,用大分页)
Page<SmErpStockEntity> bigPage = new Page<>(1, 100000);
IPage<StockWarnVO> allResult = baseMapper.selectWarnStockWithSpu(bigPage, tempQuery);
// 在内存中筛选指定的 warnType
List<StockWarnVO> filteredList = allResult.getRecords().stream()
.filter(vo -> targetWarnType.equals(vo.getWarnType()))
.collect(java.util.stream.Collectors.toList());
System.out.println("所有预警数量: " + allResult.getRecords().size() +
", warnType=" + targetWarnType + " 的数量: " + filteredList.size());
// 手动分页
int total = filteredList.size();
int pageSize = (int) page.getSize();
int current = (int) page.getCurrent();
int fromIndex = (current - 1) * pageSize;
int toIndex = Math.min(fromIndex + pageSize, total);
List<StockWarnVO> pagedList = (fromIndex < total)
? filteredList.subList(fromIndex, toIndex)
: new java.util.ArrayList<>();
Page<StockWarnVO> resultPage = new Page<>(current, pageSize, total);
resultPage.setRecords(pagedList);
return resultPage;
} else {
// 没有 warnType 参数,直接查询所有预警
return baseMapper.selectWarnStockWithSpu(page, queryDTO);
}
}
@Override
@@ -23,6 +23,7 @@
<id column="id" property="id"/>
<result column="inventory_upper_limit" property="inventoryUpperLimit"/>
<result column="inventory_lower_limit" property="inventoryLowerLimit"/>
<result column="stock" property="stock"/>
<!-- 预警类型计算字段 -->
<result column="warn_type" property="warnType"/>
@@ -30,17 +31,24 @@
<!-- SPU表关联字段 -->
<result column="product_code" property="productCode"/>
<result column="product_name" property="productName"/>
<result column="barcode" property="barcode"/>
<result column="spec" property="spec"/>
<result column="unit" property="unit"/>
<result column="package_num" property="packageNum"/>
<result column="pic_url" property="picUrl"/>
<result column="category_id" property="categoryId"/>
<!-- 包装单位表关联字段 -->
<result column="barcode" property="barCode"/>
</resultMap>
<select id="selectWarnStockWithSpu" resultMap="stockWarnResultMap">
SELECT
SELECT DISTINCT
stock.inventory_upper_limit,
stock.inventory_lower_limit,
stock.current_stock as stock,
spu.product_code,
spu.product_name,
spu.bar_code,
(SELECT bar_code FROM sm_erp_unit WHERE spu_id = spu.id AND is_base = 1 LIMIT 1) as barcode,
spu.spec,
spu.unit,
spu.package_num,
@@ -48,23 +56,31 @@
spu.category_id,
spu.id,
CASE
WHEN (stock.current_stock) > stock.inventory_upper_limit THEN '2'
ELSE '1'
WHEN stock.current_stock &lt; stock.inventory_lower_limit THEN '1'
WHEN stock.current_stock &gt; stock.inventory_upper_limit THEN '2'
ELSE NULL
END AS warn_type
FROM sm_erp_stock stock
LEFT JOIN sm_erp_spu spu ON stock.erp_spu_id = spu.id
<where>
<!-- 库存预警条件 -->
(stock.current_stock) &lt; stock.inventory_lower_limit or ( stock.current_stock) > stock.inventory_upper_limit
<if test="param.productCode != null and param.productCode != ''">
AND spu.product_code = #{param.productCode}
(stock.current_stock &lt; stock.inventory_lower_limit OR stock.current_stock &gt; stock.inventory_upper_limit)
<if test="query != null and query.productCode != null and query.productCode != ''">
AND spu.product_code LIKE CONCAT('%', #{query.productCode}, '%')
</if>
<if test="param.barcode != null and param.barcode != ''">
AND spu.bar_code = #{param.barCode}
<if test="query != null and query.barcode != null and query.barcode != ''">
AND EXISTS (
SELECT 1 FROM sm_erp_unit u
WHERE u.spu_id = spu.id
AND u.is_base = 1
AND u.bar_code = #{query.barcode}
)
</if>
<if test="param.productName != null and param.productName != ''">
AND spu.product_name LIKE CONCAT('%', #{param.productName}, '%')
<if test="query != null and query.productName != null and query.productName != ''">
AND spu.product_name LIKE CONCAT('%', #{query.productName}, '%')
</if>
<if test="query != null and query.categoryId != null">
AND spu.category_id = #{query.categoryId}
</if>
</where>
ORDER BY stock.id DESC