库存商品功能优化,导入优化,导出优化

This commit is contained in:
zjf committed 2025-08-21 18:08:26 +08:00
1 parent 3cc5cf1925
commit 0776aa415f
12 files changed
+1413 -542

No files matched your search

@@ -0,0 +1,94 @@
package com.bsd.pjcloud.supermarket.dto.erpspu;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 新的商品导入DTO(用于测试)
* 参考图片数据结构,但根据实际系统字段调整
*/
@Data
public class SmErpSpuImportPDNewDto {
@ExcelProperty("货号")
private String productCode; // 货号
@ExcelProperty("自编码/条码")
private String barCode; // 自编码/条码
@ExcelProperty("商品名称")
private String productName; // 商品名称
@ExcelProperty("单位")
private String unit; // 单位
@ExcelProperty("产地")
private String origin; // 产地
@ExcelProperty("规格")
private String spec; // 规格
@ExcelProperty("库存")
private Double stock; // 期初库存
@ExcelProperty("盘点库存")
private Double pdStock; // 盘点库存
@ExcelProperty("盘点日期")
private String pdDate; // 盘点日期
@ExcelProperty("分类")
private String categoryName; // 分类
@ExcelProperty("装数")
private Integer packageNum; // 内装数量
@ExcelProperty("口味")
private String taste; // 口味
@ExcelProperty("进价")
private Double purchasePrice; // 进价
@ExcelProperty("零售价")
private Double retailPrice; // 零售价
@ExcelProperty("货商")
private String supplierName; // 货商
@ExcelProperty("促销价")
private Double promotionPrice; // 促销价
@ExcelProperty("商品性质")
private String productNature; // 商品性质
@ExcelProperty("成本单价")
private Double costPrice; // 成本单价
@ExcelProperty("库存上限")
private Integer inventoryUpperLimit; // 库存上限
@ExcelProperty("库存下限")
private Integer inventoryLowerLimit; // 库存下限
@ExcelProperty("商品状态")
private String status; // 商品状态(0-正常,1-停售)
// 辅助条码字段
@ExcelProperty("辅助条码1")
private String auxiliaryBarcode1; // 辅助条码1
@ExcelProperty("辅助条码2")
private String auxiliaryBarcode2; // 辅助条码2
@ExcelProperty("辅助条码3")
private String auxiliaryBarcode3; // 辅助条码3
@ExcelProperty("辅助条码4")
private String auxiliaryBarcode4; // 辅助条码4
@ExcelProperty("辅助条码5")
private String auxiliaryBarcode5; // 辅助条码5
// 注释品牌字段,暂时不使用
// @ExcelProperty("品牌")
// private String brand; // 品牌
}
@@ -33,5 +33,8 @@ public class UpdateStockDTO {
@NotNull(message = "库存变化数量不能为空")
private Double incrCount;
/**
* 包装单位ID
*/
private Long unitId;
}
@@ -94,5 +94,5 @@ public class SmErpAuxiliaryCodeEntity extends Model<SmErpAuxiliaryCodeEntity> {
@Schema(description="口味")
@TableField(exist = false)
private String taste;
private String tasteName;
}
@@ -147,11 +147,10 @@ public class SmErpUnitEntity extends Model<SmErpUnitEntity> {
@Schema(description = "是否是基础库存,默认0否,1是")
private Boolean isBase;
@Schema(description = "口味")
private String taste;
@Schema(description = "口味id")
private Long tasteId;
@Schema(description = "口味名称")
private String tasteName;
}
@@ -17,6 +17,7 @@ import com.bsd.pjcloud.supermarket.dto.SupermarketSpuQueryDTO;
import com.bsd.pjcloud.supermarket.dto.SupermarketSpuUpdateStockByCodeReqDTO;
import com.bsd.pjcloud.supermarket.dto.SupermarketSpuUpdateStockReqDTO;
import com.bsd.pjcloud.supermarket.dto.erpspu.SmErpSpuImportDto;
import com.bsd.pjcloud.supermarket.dto.erpspu.SmErpSpuImportPDNewDto;
import com.bsd.pjcloud.supermarket.dto.erpspu.SmErpSpuPageDto;
import com.bsd.pjcloud.supermarket.dto.erpspu.SmErpSpuImportNewDto;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.*;
@@ -315,7 +316,19 @@ public class SmErpSpuController {
}
return smErpSpuService.importPD(collect, bindingResult);
}
@PostMapping("/importPDNew")
@PreAuthorize("@pms.hasPermission('supermarket_supermarketSpu_import')" )
@Idempotent(expireTime = 10, info = "请勿重复导入,10秒后再重新尝试")
@Operation(summary = "新的商品盘点导入", description = "支持包装单位、辅助条码等详细信息的盘点导入,根据盘点库存更新商品库存和口味库存")
public R importPDNew(@RequestExcel List<SmErpSpuImportPDNewDto> dtos, BindingResult bindingResult) {
List<SmErpSpuImportPDNewDto> collect = dtos.stream()
.filter(dto -> StringUtils.isNotBlank(dto.getProductCode()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(collect)) {
return R.failed("导入数据不能为空");
}
return smErpSpuService.importPDNew(collect, bindingResult);
}
/**
* 条件查询spu单表 列表信息
* @param supermarketSpuQueryDTO 商品spu
@@ -49,6 +49,7 @@ public class SmErpTasteStockController {
@PreAuthorize("@pms.hasPermission('supermarket_supermarketSpu_view')" )
public R getSmErpTasteStockPage(@ParameterObject Page page, @ParameterObject SmErpTasteStockEntity smErpTasteStock) {
LambdaQueryWrapper<SmErpTasteStockEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(SmErpTasteStockEntity::getSpuId, smErpTasteStock.getSpuId());
return R.ok(smErpTasteStockService.page(page, wrapper));
}
@@ -11,6 +11,7 @@ import com.bsd.pjcloud.supermarket.dto.SupermarketSpuUpdateStockReqDTO;
import com.bsd.pjcloud.supermarket.dto.cgplan.ErpCgPlanDTO;
import com.bsd.pjcloud.supermarket.dto.erpspu.SmErpSpuImportDto;
import com.bsd.pjcloud.supermarket.dto.erpspu.SmErpSpuImportNewDto;
import com.bsd.pjcloud.supermarket.dto.erpspu.SmErpSpuImportPDNewDto;
import com.bsd.pjcloud.supermarket.dto.erpspu.SmErpSpuPageDto;
import com.bsd.pjcloud.supermarket.dto.inventoryrecords.PdExcelImportDto;
import com.bsd.pjcloud.supermarket.entity.SmErpSpuEntity;
@@ -138,6 +139,14 @@ public interface SmErpSpuService extends IService<SmErpSpuEntity> {
*/
R importPD(List<PdExcelImportDto> dtos, BindingResult bindingResult);
/**
* 新的盘点导入方法
* @param smErpSpuImportPDNewDtos 导入数据列表
* @param bindingResult 错误信息列表
* @return R
*/
R importPDNew(List<SmErpSpuImportPDNewDto> smErpSpuImportPDNewDtos, BindingResult bindingResult);
/**
* 导出
@@ -5,4 +5,19 @@ import com.bsd.pjcloud.supermarket.entity.SmErpTasteStockEntity;
public interface SmErpTasteStockService extends IService<SmErpTasteStockEntity> {
/**
* 扣减口味库存
* @param tasteId 口味ID
* @param quantity 扣减数量
* @return 是否扣减成功
*/
boolean decreaseTasteStock(Long tasteId, Double quantity);
/**
* 增加口味库存
* @param tasteId 口味ID
* @param quantity 增加数量
* @return 是否增加成功
*/
boolean increaseTasteStock(Long tasteId, Double quantity);
}
@@ -0,0 +1,94 @@
package com.bsd.pjcloud.supermarket.dto.erpspu;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 新的商品导入DTO(用于测试)
* 参考图片数据结构,但根据实际系统字段调整
*/
@Data
public class SmErpSpuImportPDNewDto {
@ExcelProperty("货号")
private String productCode; // 货号
@ExcelProperty("自编码/条码")
private String barCode; // 自编码/条码
@ExcelProperty("商品名称")
private String productName; // 商品名称
@ExcelProperty("单位")
private String unit; // 单位
@ExcelProperty("产地")
private String origin; // 产地
@ExcelProperty("规格")
private String spec; // 规格
@ExcelProperty("库存")
private Double stock; // 期初库存
@ExcelProperty("盘点库存")
private Double pdStock; // 盘点库存(包装单位级别)
@ExcelProperty("盘点日期")
private String pdDate; // 盘点日期
@ExcelProperty("分类")
private String categoryName; // 分类
@ExcelProperty("装数")
private Integer packageNum; // 内装数量
@ExcelProperty("口味")
private String taste; // 口味
@ExcelProperty("进价")
private Double purchasePrice; // 进价
@ExcelProperty("零售价")
private Double retailPrice; // 零售价
@ExcelProperty("货商")
private String supplierName; // 货商
@ExcelProperty("促销价")
private Double promotionPrice; // 促销价
@ExcelProperty("商品性质")
private String productNature; // 商品性质
@ExcelProperty("成本单价")
private Double costPrice; // 成本单价
@ExcelProperty("库存上限")
private Integer inventoryUpperLimit; // 库存上限
@ExcelProperty("库存下限")
private Integer inventoryLowerLimit; // 库存下限
@ExcelProperty("商品状态")
private String status; // 商品状态(0-正常,1-停售)
// 辅助条码字段
@ExcelProperty("辅助条码1")
private String auxiliaryBarcode1; // 辅助条码1
@ExcelProperty("辅助条码2")
private String auxiliaryBarcode2; // 辅助条码2
@ExcelProperty("辅助条码3")
private String auxiliaryBarcode3; // 辅助条码3
@ExcelProperty("辅助条码4")
private String auxiliaryBarcode4; // 辅助条码4
@ExcelProperty("辅助条码5")
private String auxiliaryBarcode5; // 辅助条码5
// 注释品牌字段,暂时不使用
// @ExcelProperty("品牌")
// private String brand; // 品牌
}
@@ -8,9 +8,12 @@ import com.bsd.pjcloud.supermarket.dto.inventoryrecords.InventoryRecordSaveItemD
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;
import com.bsd.pjcloud.supermarket.mapper.SmErpStockMapper;
import com.bsd.pjcloud.supermarket.service.SmErpStockService;
import com.bsd.pjcloud.supermarket.service.SmErpTasteStockService;
import com.bsd.pjcloud.supermarket.service.SmErpUnitService;
import com.bsd.pjcloud.supermarket.vo.stockwarn.StockWarnVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
@@ -29,6 +32,10 @@ import java.util.List;
public class SmErpStockServiceImpl extends ServiceImpl<SmErpStockMapper, SmErpStockEntity> implements SmErpStockService {
private final SmErpSpuMapper smErpSpuMapper;
private final SmErpTasteStockService smErpTasteStockService;
private final SmErpUnitService smErpUnitService;
@Override
@@ -46,6 +53,23 @@ public class SmErpStockServiceImpl extends ServiceImpl<SmErpStockMapper, SmErpSt
item.setIncrCount(0.0);
}
// 通过包装单位ID查询口味信息
Long tasteId = null;
if (item.getUnitId() != null) {
SmErpUnitEntity unit = smErpUnitService.getById(item.getUnitId());
if (unit != null) {
tasteId = unit.getTasteId();
}
}
// 处理口味库存扣减
if (tasteId != null) {
// 有口味:先扣减口味库存(允许超卖,不检查库存是否足够)
smErpTasteStockService.decreaseTasteStock(tasteId, item.getIncrCount());
// 有口味的商品也需要扣减总库存,因为总库存包含期初库存
}
// 没有口味的商品:更新总库存
// 1. 先查询当前版本号
LambdaQueryWrapper<SmErpStockEntity> smErpStockEntityLambdaQueryWrapper = new LambdaQueryWrapper<SmErpStockEntity>();
smErpStockEntityLambdaQueryWrapper.eq(SmErpStockEntity::getErpSpuId,item.getId());
@@ -63,6 +87,5 @@ public class SmErpStockServiceImpl extends ServiceImpl<SmErpStockMapper, SmErpSt
throw new RuntimeException("库存更新冲突,请重试操作");
}
}
}
}
@@ -1,10 +1,14 @@
package com.bsd.pjcloud.supermarket.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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;
import org.springframework.transaction.annotation.Transactional;
/**
* 口味库存表
*
@@ -13,4 +17,52 @@ import org.springframework.stereotype.Service;
*/
@Service
public class SmErpTasteStockServiceImpl extends ServiceImpl<SmErpTasteStockMapper, SmErpTasteStockEntity> implements SmErpTasteStockService {
@Override
@Transactional
public boolean decreaseTasteStock(Long tasteId, Double quantity) {
if (tasteId == null || quantity == null || quantity <= 0) {
return false;
}
// 查询当前口味库存
SmErpTasteStockEntity tasteStock = this.getById(tasteId);
if (tasteStock == null) {
return false;
}
// 允许超卖:直接扣减库存,不检查库存是否足够
Double currentStock = tasteStock.getStock() != null ? tasteStock.getStock() : 0.0;
Double newStock = currentStock - quantity;
LambdaUpdateWrapper<SmErpTasteStockEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(SmErpTasteStockEntity::getId, tasteId)
.set(SmErpTasteStockEntity::getStock, newStock);
return this.update(updateWrapper);
}
@Override
@Transactional
public boolean increaseTasteStock(Long tasteId, Double quantity) {
if (tasteId == null || quantity == null || quantity <= 0) {
return false;
}
// 查询当前口味库存
SmErpTasteStockEntity tasteStock = this.getById(tasteId);
if (tasteStock == null) {
return false;
}
// 增加库存
Double currentStock = tasteStock.getStock() != null ? tasteStock.getStock() : 0.0;
Double newStock = currentStock + quantity;
LambdaUpdateWrapper<SmErpTasteStockEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(SmErpTasteStockEntity::getId, tasteId)
.set(SmErpTasteStockEntity::getStock, newStock);
return this.update(updateWrapper);
}
}