超市库存商品,口味重构

This commit is contained in:
zjf committed 2025-08-19 12:43:50 +08:00
1 parent 8b5f776f1a
commit 5af2e04443
8 files changed
+301 -32

No files matched your search

@@ -150,4 +150,8 @@ public class SmErpUnitEntity extends Model<SmErpUnitEntity> {
@Schema(description = "口味")
private String taste;
@Schema(description = "当前包装单位的库存")
private Double stock;
}
@@ -0,0 +1,119 @@
package com.bsd.pjcloud.supermarket.controller;
import cn.hutool.core.util.ArrayUtil;
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.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.supermarket.entity.SmErpTasteStockEntity;
import com.bsd.pjcloud.supermarket.service.SmErpTasteStockService;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
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 lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Objects;
/**
* 口味库存表
*
* @author zjf
* @date 2025-08-19 11:57:22
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/smErpTasteStock" )
@Tag(description = "smErpTasteStock" , name = "口味库存表管理" )
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class SmErpTasteStockController {
private final SmErpTasteStockService smErpTasteStockService;
/**
* 分页查询
* @param page 分页对象
* @param smErpTasteStock 口味库存表
* @return
*/
@Operation(summary = "分页查询" , description = "分页查询" )
@GetMapping("/page" )
@PreAuthorize("@pms.hasPermission('supermarket_smErpTasteStock_view')" )
public R getSmErpTasteStockPage(@ParameterObject Page page, @ParameterObject SmErpTasteStockEntity smErpTasteStock) {
LambdaQueryWrapper<SmErpTasteStockEntity> wrapper = Wrappers.lambdaQuery();
return R.ok(smErpTasteStockService.page(page, wrapper));
}
/**
* 通过id查询口味库存表
* @param id id
* @return R
*/
@Operation(summary = "通过id查询" , description = "通过id查询" )
@GetMapping("/{id}" )
@PreAuthorize("@pms.hasPermission('supermarket_smErpTasteStock_view')" )
public R getById(@PathVariable("id" ) Long id) {
return R.ok(smErpTasteStockService.getById(id));
}
/**
* 新增口味库存表
* @param smErpTasteStock 口味库存表
* @return R
*/
@Operation(summary = "新增口味库存表" , description = "新增口味库存表" )
@SysLog("新增口味库存表" )
@PostMapping
@PreAuthorize("@pms.hasPermission('supermarket_smErpTasteStock_add')" )
public R save(@RequestBody SmErpTasteStockEntity smErpTasteStock) {
return R.ok(smErpTasteStockService.save(smErpTasteStock));
}
/**
* 修改口味库存表
* @param smErpTasteStock 口味库存表
* @return R
*/
@Operation(summary = "修改口味库存表" , description = "修改口味库存表" )
@SysLog("修改口味库存表" )
@PutMapping
@PreAuthorize("@pms.hasPermission('supermarket_smErpTasteStock_edit')" )
public R updateById(@RequestBody SmErpTasteStockEntity smErpTasteStock) {
return R.ok(smErpTasteStockService.updateById(smErpTasteStock));
}
/**
* 通过id删除口味库存表
* @param ids id列表
* @return R
*/
@Operation(summary = "通过id删除口味库存表" , description = "通过id删除口味库存表" )
@SysLog("通过id删除口味库存表" )
@DeleteMapping
@PreAuthorize("@pms.hasPermission('supermarket_smErpTasteStock_del')" )
public R removeById(@RequestBody Long[] ids) {
return R.ok(smErpTasteStockService.removeBatchByIds(CollUtil.toList(ids)));
}
/**
* 导出excel 表格
* @param smErpTasteStock 查询条件
* @param ids 导出指定ID
* @return excel 文件流
*/
@ResponseExcel
@GetMapping("/export")
@PreAuthorize("@pms.hasPermission('supermarket_smErpTasteStock_export')" )
public List<SmErpTasteStockEntity> export(SmErpTasteStockEntity smErpTasteStock,Long[] ids) {
return smErpTasteStockService.list(Wrappers.lambdaQuery(smErpTasteStock).in(ArrayUtil.isNotEmpty(ids), SmErpTasteStockEntity::getId, ids));
}
}
@@ -0,0 +1,63 @@
package com.bsd.pjcloud.supermarket.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 口味库存表
*
* @author zjf
* @date 2025-08-19 11:57:22
*/
@Data
@TableName("sm_erp_taste_stock")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "口味库存表")
public class SmErpTasteStockEntity extends Model<SmErpTasteStockEntity> {
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description="id")
private Long id;
/**
* 商品SPU ID
*/
@Schema(description="商品SPU ID")
@NotNull
private Long spuId;
/**
* 口味名称
*/
@Schema(description="口味名称")
private String taste;
/**
* 该口味的库存数量
*/
@Schema(description="该口味的库存数量")
private Double stock;
/**
* createTime
*/
@TableField(fill = FieldFill.INSERT)
@Schema(description="createTime")
private LocalDateTime createTime;
/**
* updateTime
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
@Schema(description="updateTime")
private LocalDateTime updateTime;
}
@@ -0,0 +1,11 @@
package com.bsd.pjcloud.supermarket.mapper;
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
import com.bsd.pjcloud.supermarket.entity.SmErpTasteStockEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SmErpTasteStockMapper extends PjcloudBaseMapper<SmErpTasteStockEntity> {
}
@@ -0,0 +1,8 @@
package com.bsd.pjcloud.supermarket.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.supermarket.entity.SmErpTasteStockEntity;
public interface SmErpTasteStockService extends IService<SmErpTasteStockEntity> {
}
@@ -82,6 +82,8 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
private final SmSpuMapper spuMapper;
private final SmErpUnitMapper smErpUnitMapper;
private final SmErpStockService smErpStockService;
private final SmErpCategoryMapper smErpCategoryMapper;
@@ -99,7 +101,6 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
private final SmErpInventoryRecordsItemService smErpInventoryRecordsItemService;
private final SmErpCommonService smErpCommonService;
@Autowired
@@ -384,22 +385,29 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
for (SupermarketSpuUpdateStockReqDTO.Item v : updateStockReqDTO.getItems()) {
SmErpUnitEntity smErpUnitEntity = smErpUnitService.getById(v.getId());
//计算包装单位实际需要扣减的库存
Double incrCount = (smErpUnitEntity.getPackageNum()) * v.getIncrCount();
Double incrCount1 = v.getIncrCount();
Double incrCount = (smErpUnitEntity.getPackageNum()) * incrCount1;
// 查询当前库存
Long spuId = smErpUnitEntity.getSpuId();
SmErpSpuEntity spu = baseMapper.selectById(spuId);
if (null==spu) {
return R.failed(spu.getProductName() + "商品不存在");
}
if (v.getIncrCount() == 0) {
if (incrCount1 == 0) {
return R.failed("扣减不能为0");
}
LambdaUpdateWrapper<SmErpStockEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(SmErpStockEntity::getErpSpuId, spuId);
SmErpStockEntity smErpStockEntity = smErpStockMapper.selectOne(lambdaUpdateWrapper);
//还要对当前包装单位的库存进行扣减,因为有可能这个包装单位有很多口味,每一种口味也对应着自己的库存
//先查询当前包装单位是否设置了库存,因为存在没有设置的情况,则说明不包含同种规格口味不一样的情况
if (smErpUnitEntity.getStock() != null){
smErpUnitEntity.setStock(smErpUnitEntity.getStock() -incrCount1 );
smErpUnitMapper.updateById(smErpUnitEntity);
}
//todo 要求先允许超卖,过后在入库回来
// 检查库存是否足够
// LambdaUpdateWrapper<SmErpStockEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
// lambdaUpdateWrapper.eq(SmErpStockEntity::getErpSpuId, spuId);
// SmErpStockEntity smErpStockEntity = smErpStockMapper.selectOne(lambdaUpdateWrapper);
// if (incrCount < 0 && Math.abs(incrCount) > smErpStockEntity.getCurrentStock()) {
// return R.failed(spu.getProductName() + "库存不足,无法完成操作");
// }
@@ -475,10 +483,12 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
SmErpStockEntity smErpStockEntity = smErpStockMapper.selectOne(lambdaUpdateWrapper);
//todo 要求先允许超卖,过后在入库回来
// 检查库存是否足够
if (incrCount < 0 && Math.abs(incrCount) > smErpStockEntity.getCurrentStock()) {
return R.failed(spu.getProductName() + "库存不足,无法完成操作");
}
// 检查库存是否足够
// if (incrCount < 0 && Math.abs(incrCount) > smErpStockEntity.getCurrentStock()) {
// return R.failed(spu.getProductName() + "库存不足,无法完成操作");
// }
UpdateStockDTO updateStockDTO = new UpdateStockDTO(spuId, incrCount);
updateStockDTOS.add(updateStockDTO);
@@ -1052,6 +1062,8 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
BigDecimal.valueOf(dto.getPromotionPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0);
unit.setCostPrice(dto.getCostPrice() != null ?
BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0);
// 设置包装单位自己的库存
unit.setStock(dto.getStock() != null ? dto.getStock() : 0.0);
// 检查单位是否已存在:条码优先,其次使用 单位+口味+规格 的组合
LambdaQueryWrapper<SmErpUnitEntity> existingUnitWrapper = new LambdaQueryWrapper<>();
@@ -1124,24 +1136,30 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
}
}
// 7. 处理库存设置
SmErpStockEntity stock = new SmErpStockEntity();
stock.setErpSpuId(spu.getId());
stock.setInventoryUpperLimit(dto.getInventoryUpperLimit() != null ? dto.getInventoryUpperLimit() : 1000);
stock.setInventoryLowerLimit(dto.getInventoryLowerLimit() != null ? dto.getInventoryLowerLimit() : 10);
stock.setBaseStock(dto.getStock() != null ? dto.getStock() : 0.0);
stock.setCurrentStock(dto.getStock() != null ? dto.getStock() : 0.0);
// 7. 处理库存设置 - 总库存应该是所有包装单位库存的总和
// 先查询该SPU下所有包装单位的库存总和
Double totalUnitStock = dto.getStock() != null ? dto.getStock() : 0.0;
// 检查库存记录是否已存在
LambdaQueryWrapper<SmErpStockEntity> existingStockWrapper = new LambdaQueryWrapper<>();
existingStockWrapper.eq(SmErpStockEntity::getErpSpuId, spu.getId());
SmErpStockEntity existingStock = smErpStockService.getOne(existingStockWrapper);
if (existingStock != null) {
// 库存记录已存在,记录并跳过(importNew 不覆盖库存)
errorReasons.add("货号:" + dto.getProductCode() + " 商品名称:" + dto.getProductName() + " - 库存记录已存在,跳过导入以避免覆盖线上数据");
errorList.add(createErrorInfo(rowNumber, dto.getProductCode(), errorReasons));
// 库存记录已存在,累加包装单位库存到总库存
Double currentTotalStock = existingStock.getCurrentStock() != null ? existingStock.getCurrentStock() : 0.0;
Double newTotalStock = currentTotalStock + totalUnitStock;
existingStock.setCurrentStock(newTotalStock);
existingStock.setBaseStock(newTotalStock);
smErpStockService.updateById(existingStock);
} else {
// 创建新的库存记录,总库存等于包装单位库存
SmErpStockEntity stock = new SmErpStockEntity();
stock.setErpSpuId(spu.getId());
stock.setInventoryUpperLimit(dto.getInventoryUpperLimit() != null ? dto.getInventoryUpperLimit() : 1000);
stock.setInventoryLowerLimit(dto.getInventoryLowerLimit() != null ? dto.getInventoryLowerLimit() : 10);
stock.setBaseStock(totalUnitStock);
stock.setCurrentStock(totalUnitStock);
smErpStockService.save(stock);
}
@@ -1278,6 +1296,8 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
BigDecimal.valueOf(dto.getPromotionPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0);
unit.setCostPrice(dto.getCostPrice() != null ?
BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0);
// 设置包装单位自己的库存
unit.setStock(dto.getStock() != null ? dto.getStock() : 0.0);
// 检查单位是否已存在(根据单位名称、口味和规格)
LambdaQueryWrapper<SmErpUnitEntity> existingUnitWrapper = new LambdaQueryWrapper<>();
@@ -1297,6 +1317,8 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
existingUnit.setRetailPrice(unit.getRetailPrice());
existingUnit.setPromotionPrice(unit.getPromotionPrice());
existingUnit.setCostPrice(unit.getCostPrice());
// 更新包装单位库存
existingUnit.setStock(unit.getStock());
smErpUnitService.updateById(existingUnit);
} else {
smErpUnitService.save(unit);
@@ -1341,27 +1363,39 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
}
}
// 7. 处理库存设置
SmErpStockEntity stock = new SmErpStockEntity();
stock.setErpSpuId(spu.getId());
stock.setInventoryUpperLimit(dto.getInventoryUpperLimit() != null ? dto.getInventoryUpperLimit() : 1000);
stock.setInventoryLowerLimit(dto.getInventoryLowerLimit() != null ? dto.getInventoryLowerLimit() : 10);
stock.setBaseStock(dto.getStock() != null ? dto.getStock() : 0.0);
stock.setCurrentStock(dto.getStock() != null ? dto.getStock() : 0.0);
// 7. 处理库存设置 - 总库存应该是所有包装单位库存的总和
// 计算该SPU下所有包装单位的库存总和
Double totalUnitStock = dto.getStock() != null ? dto.getStock() : 0.0;
// 检查库存记录是否已存在
LambdaQueryWrapper<SmErpStockEntity> existingStockWrapper = new LambdaQueryWrapper<>();
existingStockWrapper.eq(SmErpStockEntity::getErpSpuId, spu.getId());
SmErpStockEntity existingStock = smErpStockService.getOne(existingStockWrapper);
if (existingStock != null) {
// 更新现有库存记录
// 更新现有库存记录 - 重新计算总库存
// 查询该SPU下所有包装单位的库存总和
List<SmErpUnitEntity> allUnits = smErpUnitService.list(
new LambdaQueryWrapper<SmErpUnitEntity>()
.eq(SmErpUnitEntity::getSpuId, spu.getId())
);
Double totalStock = allUnits.stream()
.mapToDouble(u -> u.getStock() != null ? u.getStock() : 0.0)
.sum();
existingStock.setInventoryUpperLimit(dto.getInventoryUpperLimit() != null ? dto.getInventoryUpperLimit() : 1000);
existingStock.setInventoryLowerLimit(dto.getInventoryLowerLimit() != null ? dto.getInventoryLowerLimit() : 10);
existingStock.setBaseStock(dto.getStock() != null ? dto.getStock() : 0.0);
existingStock.setCurrentStock(dto.getStock() != null ? dto.getStock() : 0.0);
existingStock.setBaseStock(totalStock);
existingStock.setCurrentStock(totalStock);
smErpStockService.updateById(existingStock);
} else {
// 创建新的库存记录
SmErpStockEntity stock = new SmErpStockEntity();
stock.setErpSpuId(spu.getId());
stock.setInventoryUpperLimit(dto.getInventoryUpperLimit() != null ? dto.getInventoryUpperLimit() : 1000);
stock.setInventoryLowerLimit(dto.getInventoryLowerLimit() != null ? dto.getInventoryLowerLimit() : 10);
stock.setBaseStock(totalUnitStock);
stock.setCurrentStock(totalUnitStock);
smErpStockService.save(stock);
}
@@ -0,0 +1,16 @@
package com.bsd.pjcloud.supermarket.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.supermarket.entity.SmErpTasteStockEntity;
import com.bsd.pjcloud.supermarket.mapper.SmErpTasteStockMapper;
import com.bsd.pjcloud.supermarket.service.SmErpTasteStockService;
import org.springframework.stereotype.Service;
/**
* 口味库存表
*
* @author zjf
* @date 2025-08-19 11:57:22
*/
@Service
public class SmErpTasteStockServiceImpl extends ServiceImpl<SmErpTasteStockMapper, SmErpTasteStockEntity> implements SmErpTasteStockService {
}
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bsd.pjcloud.supermarket.mapper.SmErpTasteStockMapper">
<resultMap id="smErpTasteStockMap" type="com.bsd.pjcloud.supermarket.entity.SmErpTasteStockEntity">
<id property="id" column="id"/>
<result property="spuId" column="spu_id"/>
<result property="taste" column="taste"/>
<result property="stock" column="stock"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
</mapper>