From 0776aa415f31852b3e627a60512390bf9167ed76 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Thu, 21 Aug 2025 18:08:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=93=E5=AD=98=E5=95=86=E5=93=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=EF=BC=8C=E5=AF=BC=E5=85=A5=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E5=AF=BC=E5=87=BA=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/erpspu/SmErpSpuImportPDNewDto.java | 94 + .../dto/inventoryrecords/UpdateStockDTO.java | 5 +- .../entity/SmErpAuxiliaryCodeEntity.java | 2 +- .../supermarket/entity/SmErpUnitEntity.java | 7 +- .../controller/SmErpSpuController.java | 15 +- .../controller/SmErpTasteStockController.java | 1 + .../supermarket/service/SmErpSpuService.java | 9 + .../service/SmErpTasteStockService.java | 15 + .../service/impl/SmErpSpuImportPDNewDto.java | 94 + .../service/impl/SmErpSpuServiceImpl.java | 1636 +++++++++++------ .../service/impl/SmErpStockServiceImpl.java | 25 +- .../impl/SmErpTasteStockServiceImpl.java | 52 + 12 files changed, 1413 insertions(+), 542 deletions(-) create mode 100644 pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/dto/erpspu/SmErpSpuImportPDNewDto.java create mode 100644 pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuImportPDNewDto.java diff --git a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/dto/erpspu/SmErpSpuImportPDNewDto.java b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/dto/erpspu/SmErpSpuImportPDNewDto.java new file mode 100644 index 000000000..44c102aef --- /dev/null +++ b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/dto/erpspu/SmErpSpuImportPDNewDto.java @@ -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; // 品牌 +} \ No newline at end of file diff --git a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/dto/inventoryrecords/UpdateStockDTO.java b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/dto/inventoryrecords/UpdateStockDTO.java index d27d92548..80dfebb02 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/dto/inventoryrecords/UpdateStockDTO.java +++ b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/dto/inventoryrecords/UpdateStockDTO.java @@ -33,5 +33,8 @@ public class UpdateStockDTO { @NotNull(message = "库存变化数量不能为空") private Double incrCount; - + /** + * 包装单位ID + */ + private Long unitId; } diff --git a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmErpAuxiliaryCodeEntity.java b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmErpAuxiliaryCodeEntity.java index 07b48301a..0f314faa8 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmErpAuxiliaryCodeEntity.java +++ b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmErpAuxiliaryCodeEntity.java @@ -94,5 +94,5 @@ public class SmErpAuxiliaryCodeEntity extends Model { @Schema(description="口味") @TableField(exist = false) - private String taste; + private String tasteName; } \ No newline at end of file diff --git a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmErpUnitEntity.java b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmErpUnitEntity.java index 188cef8d9..acd266aff 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmErpUnitEntity.java +++ b/pjcloud-supermarket/pjcloud-supermarket-api/src/main/java/com/bsd/pjcloud/supermarket/entity/SmErpUnitEntity.java @@ -147,11 +147,10 @@ public class SmErpUnitEntity extends Model { @Schema(description = "是否是基础库存,默认0否,1是") private Boolean isBase; - @Schema(description = "口味") - private String taste; - - @Schema(description = "口味id") private Long tasteId; + @Schema(description = "口味名称") + private String tasteName; + } \ No newline at end of file diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/controller/SmErpSpuController.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/controller/SmErpSpuController.java index 5193643df..0cef2c881 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/controller/SmErpSpuController.java +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/controller/SmErpSpuController.java @@ -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 dtos, BindingResult bindingResult) { + List 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 diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/controller/SmErpTasteStockController.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/controller/SmErpTasteStockController.java index 79698ed06..6cc207f5c 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/controller/SmErpTasteStockController.java +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/controller/SmErpTasteStockController.java @@ -49,6 +49,7 @@ public class SmErpTasteStockController { @PreAuthorize("@pms.hasPermission('supermarket_supermarketSpu_view')" ) public R getSmErpTasteStockPage(@ParameterObject Page page, @ParameterObject SmErpTasteStockEntity smErpTasteStock) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(SmErpTasteStockEntity::getSpuId, smErpTasteStock.getSpuId()); return R.ok(smErpTasteStockService.page(page, wrapper)); } diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/SmErpSpuService.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/SmErpSpuService.java index 92e2304a0..6121a3f82 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/SmErpSpuService.java +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/SmErpSpuService.java @@ -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 { */ R importPD(List dtos, BindingResult bindingResult); + /** + * 新的盘点导入方法 + * @param smErpSpuImportPDNewDtos 导入数据列表 + * @param bindingResult 错误信息列表 + * @return R + */ + R importPDNew(List smErpSpuImportPDNewDtos, BindingResult bindingResult); + /** * 导出 diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/SmErpTasteStockService.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/SmErpTasteStockService.java index 464b3511f..2a0d6a841 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/SmErpTasteStockService.java +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/SmErpTasteStockService.java @@ -5,4 +5,19 @@ import com.bsd.pjcloud.supermarket.entity.SmErpTasteStockEntity; public interface SmErpTasteStockService extends IService { + /** + * 扣减口味库存 + * @param tasteId 口味ID + * @param quantity 扣减数量 + * @return 是否扣减成功 + */ + boolean decreaseTasteStock(Long tasteId, Double quantity); + + /** + * 增加口味库存 + * @param tasteId 口味ID + * @param quantity 增加数量 + * @return 是否增加成功 + */ + boolean increaseTasteStock(Long tasteId, Double quantity); } \ No newline at end of file diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuImportPDNewDto.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuImportPDNewDto.java new file mode 100644 index 000000000..76876a926 --- /dev/null +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuImportPDNewDto.java @@ -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; // 品牌 +} diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuServiceImpl.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuServiceImpl.java index fa0739df0..d6f79a808 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuServiceImpl.java +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuServiceImpl.java @@ -21,6 +21,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.UpdateStockDTO; import com.bsd.pjcloud.supermarket.dto.inventoryrecords.*; @@ -180,8 +181,8 @@ public class SmErpSpuServiceImpl extends ServiceImpl { // 根据口味名称设置口味ID - if (supermarketUnitEntity.getTaste() != null && !supermarketUnitEntity.getTaste().trim().isEmpty() && !tasteNameToIdMap.isEmpty()) { - Long tasteId = tasteNameToIdMap.get(supermarketUnitEntity.getTaste().trim()); + if (supermarketUnitEntity.getTasteName() != null && !supermarketUnitEntity.getTasteName().trim().isEmpty() && !tasteNameToIdMap.isEmpty()) { + Long tasteId = tasteNameToIdMap.get(supermarketUnitEntity.getTasteName().trim()); if (tasteId != null) { supermarketUnitEntity.setTasteId(tasteId); } @@ -384,7 +385,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl unit.getUnit() + "_" + (unit.getTaste() != null ? unit.getTaste() : ""), + unit -> unit.getUnit() + "_" + (unit.getTasteName() != null ? unit.getTasteName() : ""), unit -> unit ))); } @@ -393,7 +394,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl unit.getUnit() + "_" + (unit.getTaste() != null ? unit.getTaste() : ""), + unit -> unit.getUnit() + "_" + (unit.getTasteName() != null ? unit.getTasteName() : ""), unit -> unit ))); } @@ -401,13 +402,14 @@ public class SmErpSpuServiceImpl extends ServiceImpl lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); // lambdaUpdateWrapper.eq(SmErpStockEntity::getErpSpuId, spuId); // SmErpStockEntity smErpStockEntity = smErpStockMapper.selectOne(lambdaUpdateWrapper); +// if (incrCount smErpStockEntity.getCurrentStock()) { // return R.failed(spu.getProductName() + "库存不足,无法完成操作"); // } - UpdateStockDTO updateStockDTO = new UpdateStockDTO(spuId, incrCount); + UpdateStockDTO updateStockDTO = new UpdateStockDTO(spuId, incrCount, smErpUnitEntity.getId()); updateStockDTOS.add(updateStockDTO); //生成出入库记录 @@ -598,9 +590,10 @@ public class SmErpSpuServiceImpl extends ServiceImpl lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); lambdaUpdateWrapper.eq(SmErpStockEntity::getErpSpuId, spuId); - SmErpStockEntity smErpStockEntity = smErpStockMapper.selectOne(lambdaUpdateWrapper); +// SmErpStockEntity smErpStockEntity = smErpStockMapper.selectOne(lambdaUpdateWrapper); //todo 要求先允许超卖,过后在入库回来 @@ -610,7 +603,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl errorReasons = new ArrayList<>(); + // 按商品货号分组,处理多个包装单位的库存汇总 + Map> spuGroupMap = smErpSpuImportNewDtos.stream() + .collect(Collectors.groupingBy(SmErpSpuImportNewDto::getProductCode)); - try { - // 1. 基础数据校验 - if (StringUtils.isBlank(dto.getProductCode())) { - errorReasons.add("货号不能为空"); - } - if (StringUtils.isBlank(dto.getProductName())) { - errorReasons.add("商品名称不能为空"); - } - if (StringUtils.isBlank(dto.getUnit())) { - errorReasons.add("单位不能为空"); - } - if (dto.getPackageNum() == null || dto.getPackageNum() <= 0) { - errorReasons.add("装数必须大于0"); - } - - if (!errorReasons.isEmpty()) { - List prefixed = errorReasons.stream() - .map(msg -> "货号:" + dto.getProductCode() + " 商品名称:" + dto.getProductName() + " - " + msg) - .collect(Collectors.toList()); - errorList.add(createErrorInfo(rowNumber, dto.getProductCode(), prefixed)); - continue; - } - - // 2. 处理分类 - Long categoryId = null; - if (StringUtils.isNotBlank(dto.getCategoryName())) { - categoryId = resolveCategory(dto.getCategoryName(), errorReasons, rowNumber, dto.getProductCode(), - SecurityUtils.getUser().getDeptId(), null); - if (categoryId == null) { - List prefixed = errorReasons.stream() - .map(msg -> "货号:" + dto.getProductCode() + " 商品名称:" + dto.getProductName() + " - " + msg) - .collect(Collectors.toList()); - errorList.add(createErrorInfo(rowNumber, dto.getProductCode(), prefixed)); + // 按商品分组处理 + for (Map.Entry> entry : spuGroupMap.entrySet()) { + String productCode = entry.getKey(); + List spuDtos = entry.getValue(); + + // 处理每个商品及其包装单位 + SmErpSpuEntity spu = null; + List units = new ArrayList<>(); + Map tasteStockMap = new HashMap<>(); // 口味库存映射 + Double totalSpuStock = 0.0; // 商品总库存 + + // 第一轮:处理商品主数据和包装单位 + for (SmErpSpuImportNewDto dto : spuDtos) { + try { + // 1. 基础数据校验 + if (StringUtils.isBlank(dto.getProductCode())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("货号不能为空"))); continue; } - } - - // 3. 处理货商 - Long supplierId = null; - if (StringUtils.isNotBlank(dto.getSupplierName())) { - supplierId = resolveSupplierId(dto.getSupplierName(), errorReasons, rowNumber, dto.getProductCode()); - if (supplierId == null) { - List prefixed = errorReasons.stream() - .map(msg -> "货号:" + dto.getProductCode() + " 商品名称:" + dto.getProductName() + " - " + msg) - .collect(Collectors.toList()); - errorList.add(createErrorInfo(rowNumber, dto.getProductCode(), prefixed)); + if (StringUtils.isBlank(dto.getProductName())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("商品名称不能为空"))); + continue; + } + if (StringUtils.isBlank(dto.getUnit())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("单位不能为空"))); + continue; + } + if (dto.getPackageNum() == null || dto.getPackageNum() <= 0) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("装数必须大于0"))); continue; } - } - // 4. 检查商品是否已存在 - LambdaQueryWrapper existingSpuWrapper = new LambdaQueryWrapper<>(); - existingSpuWrapper.eq(SmErpSpuEntity::getProductCode, dto.getProductCode()); - SmErpSpuEntity existingSpu = this.getOne(existingSpuWrapper); + // 2. 处理商品主数据(只在第一次循环时处理) + if (spu == null) { + // 处理分类 + Long categoryId = null; + if (StringUtils.isNotBlank(dto.getCategoryName())) { + categoryId = resolveCategory(dto.getCategoryName(), new ArrayList<>(), + spuDtos.indexOf(dto) + 1, dto.getProductCode(), + SecurityUtils.getUser().getDeptId(), null); + } - SmErpSpuEntity spu; - if (existingSpu != null) { - // 商品已存在:不更新主数据,继续为该 SPU 处理包装单位与条码 - spu = existingSpu; - } else { - // 创建新商品 - spu = new SmErpSpuEntity(); - spu.setProductCode(dto.getProductCode()); - spu.setProductName(dto.getProductName()); - spu.setSpec(dto.getSpec()); - spu.setOrigin(dto.getOrigin()); - spu.setBarCode(dto.getBarCode()); - spu.setPurchasePrice(dto.getPurchasePrice() != null ? + // 处理货商 + Long supplierId = null; + if (StringUtils.isNotBlank(dto.getSupplierName())) { + supplierId = resolveSupplierId(dto.getSupplierName(), new ArrayList<>(), + spuDtos.indexOf(dto) + 1, dto.getProductCode()); + } + + // 检查商品是否已存在 + LambdaQueryWrapper existingSpuWrapper = new LambdaQueryWrapper<>(); + existingSpuWrapper.eq(SmErpSpuEntity::getProductCode, dto.getProductCode()); + SmErpSpuEntity existingSpu = this.getOne(existingSpuWrapper); + + if (existingSpu != null) { + spu = existingSpu; + } else { + // 创建新商品 + spu = new SmErpSpuEntity(); + spu.setProductCode(dto.getProductCode()); + spu.setProductName(dto.getProductName()); + spu.setSpec(dto.getSpec()); + spu.setOrigin(dto.getOrigin()); + spu.setBarCode(dto.getBarCode()); + spu.setPurchasePrice(dto.getPurchasePrice() != null ? + BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setRetailPrice(dto.getRetailPrice() != null ? + BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setPromotionPrice(dto.getPromotionPrice() != null ? + BigDecimal.valueOf(dto.getPromotionPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setCostPrice(dto.getCostPrice() != null ? + BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).doubleValue() : 0.0); + spu.setProductNature("电子称称重商品".equals(dto.getProductNature()) ? "2" : "1"); + spu.setStatus("停销".equals(dto.getStatus()) ? "1" : "0"); + spu.setDeptId(SecurityUtils.getUser().getDeptId()); + if (categoryId != null) { + spu.setCategoryId(categoryId); + } + if (supplierId != null) { + spu.setSupplierId(supplierId); + } + this.save(spu); + } + } + + // 3. 处理口味(如果有口味信息) + Long tasteId = null; + if (StringUtils.isNotBlank(dto.getTaste())) { + // 检查口味是否已存在 + LambdaQueryWrapper tasteWrapper = new LambdaQueryWrapper<>(); + tasteWrapper.eq(SmErpTasteStockEntity::getSpuId, spu.getId()); + tasteWrapper.eq(SmErpTasteStockEntity::getTasteName, dto.getTaste()); + SmErpTasteStockEntity existingTaste = smErpTasteStockMapper.selectOne(tasteWrapper); + + if (existingTaste != null) { + tasteId = existingTaste.getId(); + } else { + // 创建新口味 + SmErpTasteStockEntity newTaste = new SmErpTasteStockEntity(); + newTaste.setSpuId(spu.getId()); + newTaste.setTasteName(dto.getTaste()); + newTaste.setStock(0.0); // 初始设为0,后续会更新 + smErpTasteStockMapper.insert(newTaste); + tasteId = newTaste.getId(); + } + } + + // 4. 处理包装单位 + SmErpUnitEntity unit = new SmErpUnitEntity(); + unit.setSpuId(spu.getId()); + unit.setUnit(dto.getUnit()); + unit.setPackageNum(dto.getPackageNum()); + unit.setIsBase(true); // 默认为基础单位 + unit.setBarCode(org.apache.commons.lang3.StringUtils.isNotBlank(dto.getBarCode()) ? dto.getBarCode() : null); + unit.setTasteName(dto.getTaste()); // 设置口味名称 + unit.setSpec(org.apache.commons.lang3.StringUtils.isNotBlank(dto.getSpec()) ? dto.getSpec() : null); + unit.setTasteId(tasteId); // 设置口味ID + unit.setPurchasePrice(dto.getPurchasePrice() != null ? BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - spu.setRetailPrice(dto.getRetailPrice() != null ? + unit.setRetailPrice(dto.getRetailPrice() != null ? BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - spu.setPromotionPrice(dto.getPromotionPrice() != null ? + unit.setPromotionPrice(dto.getPromotionPrice() != null ? BigDecimal.valueOf(dto.getPromotionPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - spu.setCostPrice(dto.getCostPrice() != null ? - BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).doubleValue() : 0.0); - spu.setProductNature("电子称称重商品".equals(dto.getProductNature()) ? "2" : "1"); - spu.setStatus("停销".equals(dto.getStatus()) ? "1" : "0"); - spu.setDeptId(SecurityUtils.getUser().getDeptId()); - if (categoryId != null) { - spu.setCategoryId(categoryId); - } - if (supplierId != null) { - spu.setSupplierId(supplierId); - } - this.save(spu); - } + unit.setCostPrice(dto.getCostPrice() != null ? + BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - // 5. 处理口味(如果有口味信息) - Long tasteId = null; - if (StringUtils.isNotBlank(dto.getTaste())) { - // 检查口味是否已存在 - LambdaQueryWrapper tasteWrapper = new LambdaQueryWrapper<>(); - tasteWrapper.eq(SmErpTasteStockEntity::getSpuId, spu.getId()); - tasteWrapper.eq(SmErpTasteStockEntity::getTasteName, dto.getTaste()); - SmErpTasteStockEntity existingTaste = smErpTasteStockMapper.selectOne(tasteWrapper); - - if (existingTaste != null) { - tasteId = existingTaste.getId(); + // 检查单位是否已存在:条码优先,其次使用 单位+口味+规格 的组合 + LambdaQueryWrapper existingUnitWrapper = new LambdaQueryWrapper<>(); + existingUnitWrapper.eq(SmErpUnitEntity::getSpuId, spu.getId()); + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getBarCode())) { + existingUnitWrapper.eq(SmErpUnitEntity::getBarCode, dto.getBarCode()); } else { - // 创建新口味 - SmErpTasteStockEntity newTaste = new SmErpTasteStockEntity(); - newTaste.setSpuId(spu.getId()); - newTaste.setTasteName(dto.getTaste()); - smErpTasteStockMapper.insert(newTaste); - tasteId = newTaste.getId(); - } - } - - // 6. 处理包装单位 - SmErpUnitEntity unit = new SmErpUnitEntity(); - unit.setSpuId(spu.getId()); - unit.setUnit(dto.getUnit()); - unit.setPackageNum(dto.getPackageNum()); - unit.setIsBase(true); // 默认为基础单位 - unit.setBarCode(org.apache.commons.lang3.StringUtils.isNotBlank(dto.getBarCode()) ? dto.getBarCode() : null); - unit.setTaste(dto.getTaste()); // 保持兼容性 - unit.setSpec(org.apache.commons.lang3.StringUtils.isNotBlank(dto.getSpec()) ? dto.getSpec() : null); - unit.setTasteId(tasteId); // 设置口味ID - unit.setPurchasePrice(dto.getPurchasePrice() != null ? - BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - unit.setRetailPrice(dto.getRetailPrice() != null ? - BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - unit.setPromotionPrice(dto.getPromotionPrice() != null ? - 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); - - // 检查单位是否已存在:条码优先,其次使用 单位+口味+规格 的组合 - LambdaQueryWrapper existingUnitWrapper = new LambdaQueryWrapper<>(); - existingUnitWrapper.eq(SmErpUnitEntity::getSpuId, spu.getId()); - if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getBarCode())) { - existingUnitWrapper.eq(SmErpUnitEntity::getBarCode, dto.getBarCode()); + existingUnitWrapper.eq(SmErpUnitEntity::getUnit, dto.getUnit()); + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getTaste())) { + existingUnitWrapper.eq(SmErpUnitEntity::getTasteName, dto.getTaste()); } else { - existingUnitWrapper.eq(SmErpUnitEntity::getUnit, dto.getUnit()); - if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getTaste())) { - existingUnitWrapper.eq(SmErpUnitEntity::getTaste, dto.getTaste()); - } else { - existingUnitWrapper.and(w -> w.isNull(SmErpUnitEntity::getTaste).or().eq(SmErpUnitEntity::getTaste, "")); - } + existingUnitWrapper.and(w -> w.isNull(SmErpUnitEntity::getTasteName).or().eq(SmErpUnitEntity::getTasteName, "")); + } if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getSpec())) { existingUnitWrapper.eq(SmErpUnitEntity::getSpec, dto.getSpec()); } else { @@ -1230,14 +1225,16 @@ public class SmErpSpuServiceImpl extends ServiceImpl auxiliaryBarcodes = new ArrayList<>(); if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode1())) { auxiliaryBarcodes.add(dto.getAuxiliaryBarcode1()); @@ -1265,7 +1262,8 @@ public class SmErpSpuServiceImpl extends ServiceImpl 0) { - // 更新口味库存记录 - SmErpTasteStockEntity tasteStock = smErpTasteStockMapper.selectById(tasteId); - if (tasteStock != null) { - tasteStock.setStock(dto.getStock()); - tasteStock.setId(tasteId); // 设置包装单位ID - smErpTasteStockMapper.updateById(tasteStock); - } - } - - // 9. 处理基础库存设置 - // 检查库存记录是否已存在 - LambdaQueryWrapper existingStockWrapper = new LambdaQueryWrapper<>(); - existingStockWrapper.eq(SmErpStockEntity::getErpSpuId, spu.getId()); - SmErpStockEntity existingStock = smErpStockService.getOne(existingStockWrapper); - - if (existingStock != null) { - // 库存记录已存在,重新计算总库存 - Double newTotalStock; - - if (tasteId != null) { - // 有口味:统计所有口味库存的总和 - List allTasteStocks = smErpTasteStockMapper.selectList( - new LambdaQueryWrapper() - .eq(SmErpTasteStockEntity::getSpuId, spu.getId()) - ); - newTotalStock = allTasteStocks.stream() - .mapToDouble(ts -> ts.getStock() != null ? ts.getStock() : 0.0) - .sum(); - } else { - // 无口味:累加当前导入的库存 - Double currentTotalStock = existingStock.getCurrentStock() != null ? existingStock.getCurrentStock() : 0.0; - newTotalStock = currentTotalStock + (dto.getStock() != null ? dto.getStock() : 0.0); - } - - 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); - - if (tasteId != null) { - // 有口味:使用口味库存 - stock.setBaseStock(dto.getStock() != null ? dto.getStock() : 0.0); - stock.setCurrentStock(dto.getStock() != null ? dto.getStock() : 0.0); - } else { - // 无口味:直接使用导入的库存 - stock.setBaseStock(dto.getStock() != null ? dto.getStock() : 0.0); - stock.setCurrentStock(dto.getStock() != null ? dto.getStock() : 0.0); - } - - smErpStockService.save(stock); - } - - successList.add(spu); - successCount++; - - } catch (Exception e) { - errorReasons.add("处理失败: " + e.getMessage()); - errorList.add(createErrorInfo(rowNumber, dto.getProductCode(), errorReasons)); - } - } - - return buildImportResult(totalCount, successCount, errorList); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public R importErpSpuNewUpdate(List smErpSpuImportNewDtos, BindingResult bindingResult) { - if (CollectionUtils.isEmpty(smErpSpuImportNewDtos)) { - return R.failed("导入数据不能为空"); - } - - List> errorList = new ArrayList<>(); - List successList = new ArrayList<>(); - int totalCount = smErpSpuImportNewDtos.size(); - int successCount = 0; - - for (int i = 0; i < smErpSpuImportNewDtos.size(); i++) { - int rowNumber = i + 1; - SmErpSpuImportNewDto dto = smErpSpuImportNewDtos.get(i); - List errorReasons = new ArrayList<>(); - - try { - // 1. 基础数据校验 - if (StringUtils.isBlank(dto.getProductCode())) { - errorReasons.add("货号不能为空"); - } - if (StringUtils.isBlank(dto.getProductName())) { - errorReasons.add("商品名称不能为空"); - } - if (StringUtils.isBlank(dto.getUnit())) { - errorReasons.add("单位不能为空"); - } - if (dto.getPackageNum() == null || dto.getPackageNum() <= 0) { - errorReasons.add("装数必须大于0"); - } - - if (!errorReasons.isEmpty()) { - List prefixed = errorReasons.stream() - .map(msg -> "货号:" + dto.getProductCode() + " 商品名称:" + dto.getProductName() + " - " + msg) - .collect(Collectors.toList()); - errorList.add(createErrorInfo(rowNumber, dto.getProductCode(), prefixed)); - continue; - } - - // 2. 处理分类 - Long categoryId = null; - if (StringUtils.isNotBlank(dto.getCategoryName())) { - categoryId = resolveCategory(dto.getCategoryName(), errorReasons, rowNumber, dto.getProductCode(), - SecurityUtils.getUser().getDeptId(), null); - if (categoryId == null) { - List prefixed = errorReasons.stream() - .map(msg -> "货号:" + dto.getProductCode() + " 商品名称:" + dto.getProductName() + " - " + msg) - .collect(Collectors.toList()); - errorList.add(createErrorInfo(rowNumber, dto.getProductCode(), prefixed)); - continue; - } - } - - // 3. 处理货商 - Long supplierId = null; - if (StringUtils.isNotBlank(dto.getSupplierName())) { - supplierId = resolveSupplierId(dto.getSupplierName(), errorReasons, rowNumber, dto.getProductCode()); - if (supplierId == null) { - List prefixed = errorReasons.stream() - .map(msg -> "货号:" + dto.getProductCode() + " 商品名称:" + dto.getProductName() + " - " + msg) - .collect(Collectors.toList()); - errorList.add(createErrorInfo(rowNumber, dto.getProductCode(), prefixed)); - continue; - } - } - - // 4. 检查商品是否已存在 - LambdaQueryWrapper existingSpuWrapper = new LambdaQueryWrapper<>(); - existingSpuWrapper.eq(SmErpSpuEntity::getProductCode, dto.getProductCode()); - SmErpSpuEntity existingSpu = this.getOne(existingSpuWrapper); - - SmErpSpuEntity spu; - if (existingSpu != null) { - // 商品已存在:不更新主数据,继续为该 SPU 处理包装单位与条码 - spu = existingSpu; - } else { - // 创建新商品 - spu = new SmErpSpuEntity(); - spu.setProductCode(dto.getProductCode()); - spu.setProductName(dto.getProductName()); - spu.setSpec(dto.getSpec()); - spu.setOrigin(dto.getOrigin()); - spu.setBarCode(dto.getBarCode()); - spu.setPurchasePrice(dto.getPurchasePrice() != null ? - BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - spu.setRetailPrice(dto.getRetailPrice() != null ? - BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - spu.setPromotionPrice(dto.getPromotionPrice() != null ? - BigDecimal.valueOf(dto.getPromotionPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - spu.setCostPrice(dto.getCostPrice() != null ? - BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).doubleValue() : 0.0); - spu.setProductNature("电子称称重商品".equals(dto.getProductNature()) ? "2" : "1"); - spu.setStatus("停销".equals(dto.getStatus()) ? "1" : "0"); - spu.setDeptId(SecurityUtils.getUser().getDeptId()); - if (categoryId != null) { - spu.setCategoryId(categoryId); - } - if (supplierId != null) { - spu.setSupplierId(supplierId); - } - this.save(spu); - } - - // 5. 处理口味(如果有口味信息) - Long tasteId = null; - if (StringUtils.isNotBlank(dto.getTaste())) { - // 检查口味是否已存在 - LambdaQueryWrapper tasteWrapper = new LambdaQueryWrapper<>(); - tasteWrapper.eq(SmErpTasteStockEntity::getSpuId, spu.getId()); - tasteWrapper.eq(SmErpTasteStockEntity::getTasteName, dto.getTaste()); - SmErpTasteStockEntity existingTaste = smErpTasteStockMapper.selectOne(tasteWrapper); - - if (existingTaste != null) { - tasteId = existingTaste.getId(); - } else { - // 创建新口味 - SmErpTasteStockEntity newTaste = new SmErpTasteStockEntity(); - newTaste.setSpuId(spu.getId()); - newTaste.setTasteName(dto.getTaste()); - smErpTasteStockMapper.insert(newTaste); - tasteId = newTaste.getId(); - } - } - - // 6. 处理包装单位 - SmErpUnitEntity unit = new SmErpUnitEntity(); - unit.setSpuId(spu.getId()); - unit.setUnit(dto.getUnit()); - unit.setPackageNum(dto.getPackageNum()); - unit.setIsBase(true); // 默认为基础单位 - unit.setBarCode(dto.getBarCode()); // 包装单位的条码来自主条码 - unit.setTaste(dto.getTaste()); // 设置口味 - unit.setSpec(dto.getSpec()); // 设置规格字段 - unit.setTasteId(tasteId); // 设置口味ID - unit.setPurchasePrice(dto.getPurchasePrice() != null ? - BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - unit.setRetailPrice(dto.getRetailPrice() != null ? - BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); - unit.setPromotionPrice(dto.getPromotionPrice() != null ? - 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); - - // 检查单位是否已存在(根据单位名称、口味和规格) - LambdaQueryWrapper existingUnitWrapper = new LambdaQueryWrapper<>(); - existingUnitWrapper.eq(SmErpUnitEntity::getSpuId, spu.getId()) - .eq(SmErpUnitEntity::getUnit, dto.getUnit()) - .eq(SmErpUnitEntity::getTaste, dto.getTaste()) - .eq(SmErpUnitEntity::getSpec, dto.getSpec()); // 加入规格字段作为查询条件 - SmErpUnitEntity existingUnit = smErpUnitService.getOne(existingUnitWrapper); - - if (existingUnit != null) { - // 更新现有包装单位 - existingUnit.setPackageNum(dto.getPackageNum()); - existingUnit.setBarCode(dto.getBarCode()); // 更新条码 - existingUnit.setTaste(dto.getTaste()); // 更新口味 - existingUnit.setSpec(dto.getSpec()); // 更新规格 - existingUnit.setTasteId(tasteId); // 更新口味ID - existingUnit.setPurchasePrice(unit.getPurchasePrice()); - existingUnit.setRetailPrice(unit.getRetailPrice()); - existingUnit.setPromotionPrice(unit.getPromotionPrice()); - existingUnit.setCostPrice(unit.getCostPrice()); - smErpUnitService.updateById(existingUnit); - unit = existingUnit; // 使用更新后的单位 - } else { - smErpUnitService.save(unit); - } - - // 7. 处理辅助条码(多个辅助条码) - List auxiliaryBarcodes = new ArrayList<>(); - if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode1())) { - auxiliaryBarcodes.add(dto.getAuxiliaryBarcode1()); - } - if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode2())) { - auxiliaryBarcodes.add(dto.getAuxiliaryBarcode2()); - } - if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode3())) { - auxiliaryBarcodes.add(dto.getAuxiliaryBarcode3()); - } - if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode4())) { - auxiliaryBarcodes.add(dto.getAuxiliaryBarcode4()); - } - if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode5())) { - auxiliaryBarcodes.add(dto.getAuxiliaryBarcode5()); - } - - // 为每个辅助条码创建记录 - for (String auxiliaryBarcode : auxiliaryBarcodes) { - // 检查辅助条码是否已存在 - LambdaQueryWrapper existingBarcodeWrapper = new LambdaQueryWrapper<>(); - existingBarcodeWrapper.eq(SmErpAuxiliaryCodeEntity::getSpuId, spu.getId()) - .eq(SmErpAuxiliaryCodeEntity::getBarCode, auxiliaryBarcode); - SmErpAuxiliaryCodeEntity existingBarcode = smErpAuxiliaryCodeService.getOne(existingBarcodeWrapper); - - if (existingBarcode != null) { - // 更新现有辅助条码 - existingBarcode.setUnitId(unit.getId()); - smErpAuxiliaryCodeService.updateById(existingBarcode); - } else { - SmErpAuxiliaryCodeEntity auxiliaryCode = new SmErpAuxiliaryCodeEntity(); - auxiliaryCode.setSpuId(spu.getId()); - auxiliaryCode.setBarCode(auxiliaryBarcode); - auxiliaryCode.setUnitId(unit.getId()); - smErpAuxiliaryCodeService.save(auxiliaryCode); - } - } - - // 8. 处理口味库存(如果有口味信息) - if (tasteId != null && dto.getStock() != null && dto.getStock() > 0) { - // 更新口味库存记录 - SmErpTasteStockEntity tasteStock = smErpTasteStockMapper.selectById(tasteId); - if (tasteStock != null) { - tasteStock.setStock(dto.getStock()); - tasteStock.setId(tasteId); - smErpTasteStockMapper.updateById(tasteStock); - } - } - - // 9. 处理基础库存设置 - 总库存应该是所有包装单位口味的库存的总和 - // 计算该SPU下所有包装单位的库存总和 - Double totalUnitStock = dto.getStock() != null ? dto.getStock() : 0.0; + // 6. 关键逻辑:库存数量转换和汇总 + // 将包装单位的库存乘以内装数,然后累加到商品总库存 + Double unitStock = dto.getStock() != null ? dto.getStock() : 0.0; + Double unitActualStock = unitStock * dto.getPackageNum(); - // 检查库存记录是否已存在 + // 7. 更新口味库存(如果有口味) + if (tasteId != null) { + // 累加同一口味的库存 + tasteStockMap.merge(dto.getTaste(), unitActualStock, Double::sum); + } + + // 8. 累加到商品总库存 + totalSpuStock += unitActualStock; + + } catch (Exception e) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("处理失败: " + e.getMessage()))); + continue; + } + } + + // 第二轮:更新口味库存和商品总库存 + if (spu != null && !units.isEmpty()) { + try { + // 更新口味库存 + for (Map.Entry tasteEntry : tasteStockMap.entrySet()) { + String tasteName = tasteEntry.getKey(); + Double totalTasteStock = tasteEntry.getValue(); + + LambdaQueryWrapper tasteWrapper = new LambdaQueryWrapper<>(); + tasteWrapper.eq(SmErpTasteStockEntity::getSpuId, spu.getId()) + .eq(SmErpTasteStockEntity::getTasteName, tasteName); + SmErpTasteStockEntity tasteStock = smErpTasteStockMapper.selectOne(tasteWrapper); + + if (tasteStock != null) { + tasteStock.setStock(totalTasteStock); + smErpTasteStockMapper.updateById(tasteStock); + } + } + + // 更新商品总库存 LambdaQueryWrapper existingStockWrapper = new LambdaQueryWrapper<>(); existingStockWrapper.eq(SmErpStockEntity::getErpSpuId, spu.getId()); SmErpStockEntity existingStock = smErpStockService.getOne(existingStockWrapper); if (existingStock != null) { - // 更新现有库存记录 - 重新计算总库存 - Double totalStock; - - if (tasteId != null) { - // 有口味:统计所有口味库存的总和 - List allTasteStocks = smErpTasteStockMapper.selectList( - new LambdaQueryWrapper() - .eq(SmErpTasteStockEntity::getSpuId, spu.getId()) - ); - totalStock = allTasteStocks.stream() - .mapToDouble(ts -> ts.getStock() != null ? ts.getStock() : 0.0) - .sum(); - } else { - // 无口味:直接使用当前导入的库存数量 - totalStock = dto.getStock() != null ? dto.getStock() : 0.0; - } - - existingStock.setInventoryUpperLimit(dto.getInventoryUpperLimit() != null ? dto.getInventoryUpperLimit() : 1000); - existingStock.setInventoryLowerLimit(dto.getInventoryLowerLimit() != null ? dto.getInventoryLowerLimit() : 10); - existingStock.setBaseStock(totalStock); - existingStock.setCurrentStock(totalStock); + existingStock.setInventoryUpperLimit(1000); // 默认值 + existingStock.setInventoryLowerLimit(10); // 默认值 + existingStock.setBaseStock(totalSpuStock); + existingStock.setCurrentStock(totalSpuStock); 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); - - if (tasteId != null) { - // 有口味:使用口味库存 - stock.setBaseStock(dto.getStock() != null ? dto.getStock() : 0.0); - stock.setCurrentStock(dto.getStock() != null ? dto.getStock() : 0.0); - } else { - // 无口味:直接使用导入的库存 - stock.setBaseStock(dto.getStock() != null ? dto.getStock() : 0.0); - stock.setCurrentStock(dto.getStock() != null ? dto.getStock() : 0.0); - } - + stock.setInventoryUpperLimit(1000); + stock.setInventoryLowerLimit(10); + stock.setBaseStock(totalSpuStock); + stock.setCurrentStock(totalSpuStock); smErpStockService.save(stock); } @@ -1622,14 +1339,15 @@ public class SmErpSpuServiceImpl extends ServiceImpl exportSupermarketSpuStockExcel(SmErpSpuEntity supermarketSpu, Long[] ids) { return baseMapper.exportSupermarketSpuStockExcel(supermarketSpu, ids,DataScope.of()); @@ -1657,44 +1375,103 @@ public class SmErpSpuServiceImpl extends ServiceImpl(); + } + + // 批量查询所有相关数据,避免N+1查询 + List spuIds = spuList.stream().map(SmErpSpuEntity::getId).collect(Collectors.toList()); + + // 批量查询包装单位 + List allUnits = smErpUnitService.list( + new LambdaQueryWrapper() + .in(SmErpUnitEntity::getSpuId, spuIds) + ); + + // 批量查询辅助条码 + List allAuxiliaryCodes = smErpAuxiliaryCodeService.list( + new LambdaQueryWrapper() + .in(SmErpAuxiliaryCodeEntity::getSpuId, spuIds) + ); + + // 批量查询库存信息 + List allStocks = smErpStockService.list( + new LambdaQueryWrapper() + .in(SmErpStockEntity::getErpSpuId, spuIds) + ); + + // 批量查询分类信息 + Set categoryIds = spuList.stream() + .map(SmErpSpuEntity::getCategoryId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Map categoryMap = new HashMap<>(); + if (!categoryIds.isEmpty()) { + List categories = smErpCategoryMapper.selectList( + new LambdaQueryWrapper() + .in(SmErpCategoryEntity::getId, categoryIds) + ); + categoryMap = categories.stream() + .collect(Collectors.toMap(SmErpCategoryEntity::getId, SmErpCategoryEntity::getName)); + } + + // 批量查询货商信息 + Set supplierIds = spuList.stream() + .map(SmErpSpuEntity::getSupplierId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Map supplierMap = new HashMap<>(); + if (!supplierIds.isEmpty()) { + List suppliers = smErpSupplierMapper.selectList( + new LambdaQueryWrapper() + .in(SmErpSupplierEntity::getSupplierId, supplierIds) + ); + supplierMap = suppliers.stream() + .collect(Collectors.toMap(SmErpSupplierEntity::getSupplierId, SmErpSupplierEntity::getSupplierName)); + } + + // 批量查询口味库存 + Set tasteIds = allUnits.stream() + .map(SmErpUnitEntity::getTasteId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Map tasteStockMap = new HashMap<>(); + if (!tasteIds.isEmpty()) { + List tasteStocks = smErpTasteStockMapper.selectList( + new LambdaQueryWrapper() + .in(SmErpTasteStockEntity::getId, tasteIds) + ); + tasteStockMap = tasteStocks.stream() + .collect(Collectors.toMap(SmErpTasteStockEntity::getId, Function.identity())); + } + + // 建立索引映射,提升查找效率 + Map> spuToUnitsMap = allUnits.stream() + .collect(Collectors.groupingBy(SmErpUnitEntity::getSpuId)); + + Map> spuToCodesMap = allAuxiliaryCodes.stream() + .collect(Collectors.groupingBy(SmErpAuxiliaryCodeEntity::getSpuId)); + + Map spuToStockMap = allStocks.stream() + .collect(Collectors.toMap(SmErpStockEntity::getErpSpuId, Function.identity())); + List exportList = new ArrayList<>(); for (SmErpSpuEntity spu : spuList) { // 获取包装单位信息 - List units = smErpUnitService.list( - new LambdaQueryWrapper() - .eq(SmErpUnitEntity::getSpuId, spu.getId()) - ); - + List units = spuToUnitsMap.getOrDefault(spu.getId(), new ArrayList<>()); + // 获取辅助条码信息 - List auxiliaryCodes = smErpAuxiliaryCodeService.list( - new LambdaQueryWrapper() - .eq(SmErpAuxiliaryCodeEntity::getSpuId, spu.getId()) - ); - + List auxiliaryCodes = spuToCodesMap.getOrDefault(spu.getId(), new ArrayList<>()); + // 获取库存信息 - SmErpStockEntity stock = smErpStockService.getOne( - new LambdaQueryWrapper() - .eq(SmErpStockEntity::getErpSpuId, spu.getId()) - ); - + SmErpStockEntity stock = spuToStockMap.get(spu.getId()); + // 获取分类信息 - String categoryName = null; - if (spu.getCategoryId() != null) { - SmErpCategoryEntity category = smErpCategoryMapper.selectById(spu.getCategoryId()); - if (category != null) { - categoryName = category.getName(); - } - } - + String categoryName = categoryMap.get(spu.getCategoryId()); + // 获取货商信息 - String supplierName = null; - if (spu.getSupplierId() != null) { - SmErpSupplierEntity supplier = smErpSupplierMapper.selectById(spu.getSupplierId()); - if (supplier != null) { - supplierName = supplier.getSupplierName(); - } - } + String supplierName = supplierMap.get(spu.getSupplierId()); if (units.isEmpty()) { // 如果没有包装单位,创建一个默认的 @@ -1705,7 +1482,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl> tasteGroupMap = new HashMap<>(); // key: tasteId(可为null) + for (SmErpUnitEntity u : units) { + tasteGroupMap.computeIfAbsent(u.getTasteId(), k -> new ArrayList<>()).add(u); + } + + Double totalCurrentStock = stock != null ? stock.getCurrentStock() : 0.0; + // 计算各口味的库存(若存在口味) + Map tasteIdToStock = new HashMap<>(); + double sumTasteStocks = 0.0; + for (Map.Entry> e : tasteGroupMap.entrySet()) { + Long tId = e.getKey(); + if (tId != null) { + SmErpTasteStockEntity ts = tasteStockMap.get(tId); + double tStock = ts != null && ts.getStock() != null ? ts.getStock() : 0.0; + tasteIdToStock.put(tId, tStock); + sumTasteStocks += tStock; + } + } + // 无口味分组可用库存 = 总当前库存 - 各口味库存之和 + double noTasteAvailable = totalCurrentStock - sumTasteStocks; + + // 将分配结果映射到具体unitId + Map unitIdToDistributedStock = new HashMap<>(); + + // 分配函数:从大包装到小包装,最后一个得到余数;支持负库存 + java.util.function.BiConsumer, Double> distribute = (unitList, groupStock) -> { + if (unitList == null || unitList.isEmpty()) return; + List sorted = unitList.stream() + .sorted((a, b) -> { + double pa = a.getPackageNum() != null && a.getPackageNum() > 0 ? a.getPackageNum() : 1.0; + double pb = b.getPackageNum() != null && b.getPackageNum() > 0 ? b.getPackageNum() : 1.0; + return Double.compare(pb, pa); // desc by packageNum + }) + .collect(Collectors.toList()); + double remaining = groupStock != null ? groupStock : 0.0; + for (int idx = 0; idx < sorted.size(); idx++) { + SmErpUnitEntity su = sorted.get(idx); + double pkg = su.getPackageNum() != null && su.getPackageNum() > 0 ? su.getPackageNum() : 1.0; + double qty; + boolean isLast = (idx == sorted.size() - 1); + if (isLast) { + qty = remaining; + } else { + if (remaining >= 0) { + qty = Math.floor(remaining / pkg); + } else { + qty = Math.ceil(remaining / pkg); + } + remaining -= qty * pkg; + } + unitIdToDistributedStock.put(su.getId(), qty); + } + }; + + // 先分配有口味的分组 + for (Map.Entry> e : tasteGroupMap.entrySet()) { + Long tId = e.getKey(); + if (tId != null) { + double tStock = tasteIdToStock.getOrDefault(tId, 0.0); + distribute.accept(e.getValue(), tStock); + } + } + // 再分配无口味分组 + if (tasteGroupMap.containsKey(null)) { + distribute.accept(tasteGroupMap.get(null), noTasteAvailable); + } + for (SmErpUnitEntity unit : units) { SmErpSpuImportNewDto dto = new SmErpSpuImportNewDto(); dto.setProductCode(spu.getProductCode()); @@ -1728,17 +1573,31 @@ public class SmErpSpuServiceImpl extends ServiceImpl smErpSpuImportPDNewDtos, BindingResult bindingResult) { + if (CollectionUtils.isEmpty(smErpSpuImportPDNewDtos)) { + return R.failed("导入数据不能为空"); + } + + List> errorList = new ArrayList<>(); + List successList = new ArrayList<>(); + List pdItemList = new ArrayList<>(); + int totalCount = smErpSpuImportPDNewDtos.size(); + int successCount = 0; + + // 按商品货号分组,处理多个包装单位的库存汇总 + Map> spuGroupMap = smErpSpuImportPDNewDtos.stream() + .collect(Collectors.groupingBy(SmErpSpuImportPDNewDto::getProductCode)); + + // 计算从盘点日期到当前的零售销量,用于计算实际剩余库存 + Map spuSalesMap = new HashMap<>(); + LocalDate currentDate = LocalDate.now(); + + // 收集所有盘点日期,用于计算销量 + Set allPdDates = smErpSpuImportPDNewDtos.stream() + .map(SmErpSpuImportPDNewDto::getPdDate) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); + + for (String pdDateStr : allPdDates) { + try { + LocalDate pdDate = LocalDate.parse(pdDateStr); + + // 查询从盘点日期到当前日期的零售出库记录 + LambdaQueryWrapper retailWrapper = new LambdaQueryWrapper<>(); + retailWrapper.eq(SmErpInventoryRecordsEntity::getInventoryType, "5"); // LSCK 零售出库 + retailWrapper.ge(SmErpInventoryRecordsEntity::getInventoryDate, pdDate); + retailWrapper.le(SmErpInventoryRecordsEntity::getInventoryDate, currentDate); + + List retailRecords = smErpInventoryRecordsService.list(retailWrapper); + + // 收集所有零售记录的ID + List retailRecordIds = retailRecords.stream() + .map(SmErpInventoryRecordsEntity::getId) + .collect(Collectors.toList()); + + // 查询零售出库明细 + if (!retailRecordIds.isEmpty()) { + LambdaQueryWrapper itemWrapper = new LambdaQueryWrapper<>(); + itemWrapper.in(SmErpInventoryRecordsItemEntity::getInventoryId, retailRecordIds); + List retailItems = smErpInventoryRecordsItemService.list(itemWrapper); + + // 按商品ID汇总销量 + for (SmErpInventoryRecordsItemEntity item : retailItems) { + Long spuId = item.getErpSpuId(); + Double quantity = item.getQuantity(); + spuSalesMap.merge(spuId, quantity, Double::sum); + } + } + } catch (Exception e) { + // 日期解析失败,跳过该条记录 + continue; + } + } + + // 按商品分组处理 + for (Map.Entry> entry : spuGroupMap.entrySet()) { + String productCode = entry.getKey(); + List spuDtos = entry.getValue(); + + // 处理每个商品及其包装单位 + SmErpSpuEntity spu = null; + List units = new ArrayList<>(); + Map tasteStockMap = new HashMap<>(); // 口味库存映射 + Double totalSpuStock = 0.0; // 商品总库存 + + // 第一轮:处理商品主数据和包装单位 + for (SmErpSpuImportPDNewDto dto : spuDtos) { + try { + // 1. 基础数据校验 + if (StringUtils.isBlank(dto.getProductCode())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("货号不能为空"))); + continue; + } + if (StringUtils.isBlank(dto.getProductName())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("商品名称不能为空"))); + continue; + } + if (StringUtils.isBlank(dto.getUnit())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("单位不能为空"))); + continue; + } + if (dto.getPackageNum() == null || dto.getPackageNum() <= 0) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("装数必须大于0"))); + continue; + } + if (dto.getPdStock() == null) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("盘点库存不能为空"))); + continue; + } + + // 2. 处理商品主数据(只在第一次循环时处理) + if (spu == null) { + // 处理分类 + Long categoryId = null; + if (StringUtils.isNotBlank(dto.getCategoryName())) { + categoryId = resolveCategory(dto.getCategoryName(), new ArrayList<>(), + spuDtos.indexOf(dto) + 1, dto.getProductCode(), + SecurityUtils.getUser().getDeptId(), null); + } + + // 处理货商 + Long supplierId = null; + if (StringUtils.isNotBlank(dto.getSupplierName())) { + supplierId = resolveSupplierId(dto.getSupplierName(), new ArrayList<>(), + spuDtos.indexOf(dto) + 1, dto.getProductCode()); + } + + // 检查商品是否已存在 + LambdaQueryWrapper existingSpuWrapper = new LambdaQueryWrapper<>(); + existingSpuWrapper.eq(SmErpSpuEntity::getProductCode, dto.getProductCode()); + SmErpSpuEntity existingSpu = this.getOne(existingSpuWrapper); + + if (existingSpu != null) { + spu = existingSpu; + } else { + // 创建新商品 + spu = new SmErpSpuEntity(); + spu.setProductCode(dto.getProductCode()); + spu.setProductName(dto.getProductName()); + spu.setSpec(dto.getSpec()); + spu.setOrigin(dto.getOrigin()); + spu.setBarCode(dto.getBarCode()); + spu.setPurchasePrice(dto.getPurchasePrice() != null ? + BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setRetailPrice(dto.getRetailPrice() != null ? + BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setPromotionPrice(dto.getPromotionPrice() != null ? + BigDecimal.valueOf(dto.getPromotionPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setCostPrice(dto.getCostPrice() != null ? + BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).doubleValue() : 0.0); + spu.setProductNature("电子称称重商品".equals(dto.getProductNature()) ? "2" : "1"); + spu.setStatus("停销".equals(dto.getStatus()) ? "1" : "0"); + spu.setDeptId(SecurityUtils.getUser().getDeptId()); + if (categoryId != null) { + spu.setCategoryId(categoryId); + } + if (supplierId != null) { + spu.setSupplierId(supplierId); + } + this.save(spu); + } + } + + // 3. 处理口味(如果有口味信息) + Long tasteId = null; + if (StringUtils.isNotBlank(dto.getTaste())) { + // 检查口味是否已存在 + LambdaQueryWrapper tasteWrapper = new LambdaQueryWrapper<>(); + tasteWrapper.eq(SmErpTasteStockEntity::getSpuId, spu.getId()); + tasteWrapper.eq(SmErpTasteStockEntity::getTasteName, dto.getTaste()); + SmErpTasteStockEntity existingTaste = smErpTasteStockMapper.selectOne(tasteWrapper); + + if (existingTaste != null) { + tasteId = existingTaste.getId(); + } else { + // 创建新口味 + SmErpTasteStockEntity newTaste = new SmErpTasteStockEntity(); + newTaste.setSpuId(spu.getId()); + newTaste.setTasteName(dto.getTaste()); + newTaste.setStock(0.0); // 初始设为0,后续会更新 + smErpTasteStockMapper.insert(newTaste); + tasteId = newTaste.getId(); + } + } + + // 4. 处理包装单位 + SmErpUnitEntity unit = new SmErpUnitEntity(); + unit.setSpuId(spu.getId()); + unit.setUnit(dto.getUnit()); + unit.setPackageNum(dto.getPackageNum()); + unit.setIsBase(true); // 默认为基础单位 + unit.setBarCode(dto.getBarCode()); + unit.setTasteName(dto.getTaste()); + unit.setSpec(dto.getSpec()); + unit.setTasteId(tasteId); + unit.setPurchasePrice(dto.getPurchasePrice() != null ? + BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + unit.setRetailPrice(dto.getRetailPrice() != null ? + BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + unit.setPromotionPrice(dto.getPromotionPrice() != null ? + 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); + + // 检查单位是否已存在 + SmErpUnitEntity existingUnit = null; + + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getBarCode())) { + LambdaQueryWrapper barcodeWrapper = new LambdaQueryWrapper<>(); + barcodeWrapper.eq(SmErpUnitEntity::getSpuId, spu.getId()) + .eq(SmErpUnitEntity::getBarCode, dto.getBarCode()); + existingUnit = smErpUnitService.getOne(barcodeWrapper); + } + + if (existingUnit == null) { + LambdaQueryWrapper existingUnitWrapper = new LambdaQueryWrapper<>(); + existingUnitWrapper.eq(SmErpUnitEntity::getSpuId, spu.getId()) + .eq(SmErpUnitEntity::getUnit, dto.getUnit()); + + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getTaste())) { + existingUnitWrapper.eq(SmErpUnitEntity::getTasteName, dto.getTaste()); + } else { + existingUnitWrapper.and(w -> w.isNull(SmErpUnitEntity::getTasteName).or().eq(SmErpUnitEntity::getTasteName, "")); + } + + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getSpec())) { + existingUnitWrapper.eq(SmErpUnitEntity::getSpec, dto.getSpec()); + } else { + existingUnitWrapper.and(w -> w.isNull(SmErpUnitEntity::getSpec).or().eq(SmErpUnitEntity::getSpec, "")); + } + + existingUnit = smErpUnitService.getOne(existingUnitWrapper); + } + + if (existingUnit != null) { + // 更新现有包装单位 + existingUnit.setPackageNum(dto.getPackageNum()); + existingUnit.setBarCode(dto.getBarCode()); + existingUnit.setTasteName(dto.getTaste()); + existingUnit.setSpec(dto.getSpec()); + existingUnit.setTasteId(tasteId); + existingUnit.setPurchasePrice(unit.getPurchasePrice()); + existingUnit.setRetailPrice(unit.getRetailPrice()); + existingUnit.setPromotionPrice(unit.getPromotionPrice()); + existingUnit.setCostPrice(unit.getCostPrice()); + smErpUnitService.updateById(existingUnit); + unit = existingUnit; + } else { + smErpUnitService.save(unit); + } + + units.add(unit); + + // 5. 处理辅助条码 + List auxiliaryBarcodes = new ArrayList<>(); + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode1())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode1()); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode2())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode2()); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode3())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode3()); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode4())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode4()); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode5())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode5()); + } + + for (String auxiliaryBarcode : auxiliaryBarcodes) { + LambdaQueryWrapper existingBarcodeWrapper = new LambdaQueryWrapper<>(); + existingBarcodeWrapper.eq(SmErpAuxiliaryCodeEntity::getSpuId, spu.getId()) + .eq(SmErpAuxiliaryCodeEntity::getBarCode, auxiliaryBarcode); + SmErpAuxiliaryCodeEntity existingBarcode = smErpAuxiliaryCodeService.getOne(existingBarcodeWrapper); + + if (existingBarcode != null) { + existingBarcode.setUnitId(unit.getId()); + smErpAuxiliaryCodeService.updateById(existingBarcode); + } else { + SmErpAuxiliaryCodeEntity auxiliaryCode = new SmErpAuxiliaryCodeEntity(); + auxiliaryCode.setSpuId(spu.getId()); + auxiliaryCode.setBarCode(auxiliaryBarcode); + auxiliaryCode.setUnitId(unit.getId()); + smErpAuxiliaryCodeService.save(auxiliaryCode); + } + } + + // 6. 计算包装单位的实际库存(盘点库存 × 内装数) + Double unitActualStock = dto.getPdStock() * dto.getPackageNum(); + + // 7. 更新口味库存(如果有口味) + if (tasteId != null) { + // 累加同一口味的库存 + tasteStockMap.merge(dto.getTaste(), unitActualStock, Double::sum); + } + + // 8. 累加到商品总库存 + totalSpuStock += unitActualStock; + + } catch (Exception e) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("处理失败: " + e.getMessage()))); + continue; + } + } + + // 第二轮:更新口味库存和商品总库存 + if (spu != null && !units.isEmpty()) { + try { + // 更新口味库存 + for (Map.Entry tasteEntry : tasteStockMap.entrySet()) { + String tasteName = tasteEntry.getKey(); + Double totalTasteStock = tasteEntry.getValue(); + + LambdaQueryWrapper tasteWrapper = new LambdaQueryWrapper<>(); + tasteWrapper.eq(SmErpTasteStockEntity::getSpuId, spu.getId()) + .eq(SmErpTasteStockEntity::getTasteName, tasteName); + SmErpTasteStockEntity tasteStock = smErpTasteStockMapper.selectOne(tasteWrapper); + + if (tasteStock != null) { + tasteStock.setStock(totalTasteStock); + smErpTasteStockMapper.updateById(tasteStock); + } + } + + // 更新商品总库存 + LambdaQueryWrapper existingStockWrapper = new LambdaQueryWrapper<>(); + existingStockWrapper.eq(SmErpStockEntity::getErpSpuId, spu.getId()); + SmErpStockEntity existingStock = smErpStockService.getOne(existingStockWrapper); + + if (existingStock != null) { + existingStock.setInventoryUpperLimit(1000); // 默认值 + existingStock.setInventoryLowerLimit(10); // 默认值 + existingStock.setBaseStock(totalSpuStock); + existingStock.setCurrentStock(totalSpuStock); + smErpStockService.updateById(existingStock); + } else { + SmErpStockEntity stock = new SmErpStockEntity(); + stock.setErpSpuId(spu.getId()); + stock.setInventoryUpperLimit(1000); + stock.setInventoryLowerLimit(10); + stock.setBaseStock(totalSpuStock); + stock.setCurrentStock(totalSpuStock); + smErpStockService.save(stock); + } + + successList.add(spu); + successCount++; + + } catch (Exception e) { + errorList.add(createErrorInfo(1, productCode, + Arrays.asList("库存更新失败: " + e.getMessage()))); + } + } + } + + // 如果有成功的数据,则执行导入并生成盘点单 + if (!pdItemList.isEmpty()) { + // 创建盘点主记录 + PDSaveDTO pdSaveDTO = new PDSaveDTO(); + pdSaveDTO.setInventoryCode(String.valueOf(smErpCommonService.getSequence("7"))); + pdSaveDTO.setInventoryDate(LocalDate.now()); + pdSaveDTO.setInventoryType("7"); // KCPD 库存盘点 + pdSaveDTO.setHandlerUserId(SecurityUtils.getUser().getId()); + pdSaveDTO.setItems(pdItemList); + + // 保存盘点记录 + int i = smErpInventoryRecordsService.savePD(pdSaveDTO); + if (i > 0) { + // 更新库存记录 + for (PDItemSaveDTO item : pdItemList) { + SmErpStockEntity stock = smErpStockService.getOne(new LambdaQueryWrapper() + .eq(SmErpStockEntity::getErpSpuId, item.getErpSpuId())); + + if (stock != null) { + stock.setBaseStock(item.getAccountNumber()); + stock.setCurrentStock(item.getRealNumber()); + smErpStockService.updateById(stock); + } else { + // 创建新的库存记录 + SmErpStockEntity newStock = new SmErpStockEntity(); + newStock.setErpSpuId(item.getErpSpuId()); + newStock.setBaseStock(item.getAccountNumber()); + newStock.setCurrentStock(item.getRealNumber()); + smErpStockService.save(newStock); + } + } + } + } + + return buildImportResult(totalCount, successCount, errorList); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public R importErpSpuNewUpdate(List smErpSpuImportNewDtos, BindingResult bindingResult) { + if (CollectionUtils.isEmpty(smErpSpuImportNewDtos)) { + return R.failed("导入数据不能为空"); + } + + List> errorList = new ArrayList<>(); + List successList = new ArrayList<>(); + int totalCount = smErpSpuImportNewDtos.size(); + int successCount = 0; + + // 按商品货号分组,处理多个包装单位的库存汇总 + Map> spuGroupMap = smErpSpuImportNewDtos.stream() + .collect(Collectors.groupingBy(SmErpSpuImportNewDto::getProductCode)); + + // 按商品分组处理 + for (Map.Entry> entry : spuGroupMap.entrySet()) { + String productCode = entry.getKey(); + List spuDtos = entry.getValue(); + + // 处理每个商品及其包装单位 + SmErpSpuEntity spu = null; + List units = new ArrayList<>(); + Map tasteStockMap = new HashMap<>(); // 口味库存映射 + Double totalSpuStock = 0.0; // 商品总库存 + + // 第一轮:处理商品主数据和包装单位 + for (SmErpSpuImportNewDto dto : spuDtos) { + try { + // 1. 基础数据校验 + if (StringUtils.isBlank(dto.getProductCode())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("货号不能为空"))); + continue; + } + if (StringUtils.isBlank(dto.getProductName())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("商品名称不能为空"))); + continue; + } + if (StringUtils.isBlank(dto.getUnit())) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("单位不能为空"))); + continue; + } + if (dto.getPackageNum() == null || dto.getPackageNum() <= 0) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("装数必须大于0"))); + continue; + } + + // 2. 处理商品主数据(只在第一次循环时处理) + if (spu == null) { + // 处理分类 + Long categoryId = null; + if (StringUtils.isNotBlank(dto.getCategoryName())) { + categoryId = resolveCategory(dto.getCategoryName(), new ArrayList<>(), + spuDtos.indexOf(dto) + 1, dto.getProductCode(), + SecurityUtils.getUser().getDeptId(), null); + } + + // 处理货商 + Long supplierId = null; + if (StringUtils.isNotBlank(dto.getSupplierName())) { + supplierId = resolveSupplierId(dto.getSupplierName(), new ArrayList<>(), + spuDtos.indexOf(dto) + 1, dto.getProductCode()); + } + + // 检查商品是否已存在 + LambdaQueryWrapper existingSpuWrapper = new LambdaQueryWrapper<>(); + existingSpuWrapper.eq(SmErpSpuEntity::getProductCode, dto.getProductCode()); + SmErpSpuEntity existingSpu = this.getOne(existingSpuWrapper); + + if (existingSpu != null) { + // 商品已存在:更新主数据 + spu = existingSpu; + spu.setProductName(dto.getProductName()); + spu.setSpec(dto.getSpec()); + spu.setOrigin(dto.getOrigin()); + spu.setBarCode(dto.getBarCode()); + spu.setPurchasePrice(dto.getPurchasePrice() != null ? + BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setRetailPrice(dto.getRetailPrice() != null ? + BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setPromotionPrice(dto.getPromotionPrice() != null ? + BigDecimal.valueOf(dto.getPromotionPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setCostPrice(dto.getCostPrice() != null ? + BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).doubleValue() : 0.0); + spu.setProductNature("电子称称重商品".equals(dto.getProductNature()) ? "2" : "1"); + spu.setStatus("停销".equals(dto.getStatus()) ? "1" : "0"); + if (categoryId != null) { + spu.setCategoryId(categoryId); + } + if (supplierId != null) { + spu.setSupplierId(supplierId); + } + this.updateById(spu); + } else { + // 创建新商品 + spu = new SmErpSpuEntity(); + spu.setProductCode(dto.getProductCode()); + spu.setProductName(dto.getProductName()); + spu.setSpec(dto.getSpec()); + spu.setOrigin(dto.getOrigin()); + spu.setBarCode(dto.getBarCode()); + spu.setPurchasePrice(dto.getPurchasePrice() != null ? + BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setRetailPrice(dto.getRetailPrice() != null ? + BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setPromotionPrice(dto.getPromotionPrice() != null ? + BigDecimal.valueOf(dto.getPromotionPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + spu.setCostPrice(dto.getCostPrice() != null ? + BigDecimal.valueOf(dto.getCostPrice()).multiply(BigDecimal.valueOf(100)).doubleValue() : 0.0); + spu.setProductNature("电子称称重商品".equals(dto.getProductNature()) ? "2" : "1"); + spu.setStatus("停销".equals(dto.getStatus()) ? "1" : "0"); + spu.setDeptId(SecurityUtils.getUser().getDeptId()); + if (categoryId != null) { + spu.setCategoryId(categoryId); + } + if (supplierId != null) { + spu.setSupplierId(supplierId); + } + this.save(spu); + } + } + + // 3. 处理口味(如果有口味信息) + Long tasteId = null; + if (StringUtils.isNotBlank(dto.getTaste())) { + // 检查口味是否已存在 + LambdaQueryWrapper tasteWrapper = new LambdaQueryWrapper<>(); + tasteWrapper.eq(SmErpTasteStockEntity::getSpuId, spu.getId()); + tasteWrapper.eq(SmErpTasteStockEntity::getTasteName, dto.getTaste()); + SmErpTasteStockEntity existingTaste = smErpTasteStockMapper.selectOne(tasteWrapper); + + if (existingTaste != null) { + tasteId = existingTaste.getId(); + } else { + // 创建新口味 + SmErpTasteStockEntity newTaste = new SmErpTasteStockEntity(); + newTaste.setSpuId(spu.getId()); + newTaste.setTasteName(dto.getTaste()); + newTaste.setStock(0.0); // 初始设为0,后续会更新 + smErpTasteStockMapper.insert(newTaste); + tasteId = newTaste.getId(); + } + } + + // 4. 处理包装单位 + SmErpUnitEntity unit = new SmErpUnitEntity(); + unit.setSpuId(spu.getId()); + unit.setUnit(dto.getUnit()); + unit.setPackageNum(dto.getPackageNum()); + unit.setIsBase(true); // 默认为基础单位 + unit.setBarCode(org.apache.commons.lang3.StringUtils.isNotBlank(dto.getBarCode()) ? dto.getBarCode() : null); + unit.setTasteName(dto.getTaste()); // 设置口味名称 + unit.setSpec(org.apache.commons.lang3.StringUtils.isNotBlank(dto.getSpec()) ? dto.getSpec() : null); + unit.setTasteId(tasteId); // 设置口味ID + unit.setPurchasePrice(dto.getPurchasePrice() != null ? + BigDecimal.valueOf(dto.getPurchasePrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + unit.setRetailPrice(dto.getRetailPrice() != null ? + BigDecimal.valueOf(dto.getRetailPrice()).multiply(BigDecimal.valueOf(100)).intValue() : 0); + unit.setPromotionPrice(dto.getPromotionPrice() != null ? + 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); + + // 检查单位是否已存在:条码优先,其次使用 单位+口味+规格 的组合 + LambdaQueryWrapper existingUnitWrapper = new LambdaQueryWrapper<>(); + existingUnitWrapper.eq(SmErpUnitEntity::getSpuId, spu.getId()); + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getBarCode())) { + existingUnitWrapper.eq(SmErpUnitEntity::getBarCode, dto.getBarCode()); + } else { + existingUnitWrapper.eq(SmErpUnitEntity::getUnit, dto.getUnit()); + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getTaste())) { + existingUnitWrapper.eq(SmErpUnitEntity::getTasteName, dto.getTaste()); + } else { + existingUnitWrapper.and(w -> w.isNull(SmErpUnitEntity::getTasteName).or().eq(SmErpUnitEntity::getTasteName, "")); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getSpec())) { + existingUnitWrapper.eq(SmErpUnitEntity::getSpec, dto.getSpec()); + } else { + existingUnitWrapper.and(w -> w.isNull(SmErpUnitEntity::getSpec).or().eq(SmErpUnitEntity::getSpec, "")); + } + } + SmErpUnitEntity existingUnit = smErpUnitService.getOne(existingUnitWrapper); + + if (existingUnit != null) { + // 包装单位已存在:更新现有数据 + existingUnit.setPackageNum(dto.getPackageNum()); + existingUnit.setBarCode(dto.getBarCode()); + existingUnit.setTasteName(dto.getTaste()); + existingUnit.setSpec(dto.getSpec()); + existingUnit.setTasteId(tasteId); + existingUnit.setPurchasePrice(unit.getPurchasePrice()); + existingUnit.setRetailPrice(unit.getRetailPrice()); + existingUnit.setPromotionPrice(unit.getPromotionPrice()); + existingUnit.setCostPrice(unit.getCostPrice()); + smErpUnitService.updateById(existingUnit); + unit = existingUnit; + } else { + smErpUnitService.save(unit); + } + + units.add(unit); + + // 5. 处理辅助条码(多个辅助条码) + List auxiliaryBarcodes = new ArrayList<>(); + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode1())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode1()); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode2())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode2()); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode3())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode3()); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode4())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode4()); + } + if (org.apache.commons.lang3.StringUtils.isNotBlank(dto.getAuxiliaryBarcode5())) { + auxiliaryBarcodes.add(dto.getAuxiliaryBarcode5()); + } + + // 为每个辅助条码创建记录 + for (String auxiliaryBarcode : auxiliaryBarcodes) { + // 检查辅助条码是否已存在 + LambdaQueryWrapper existingBarcodeWrapper = new LambdaQueryWrapper<>(); + existingBarcodeWrapper.eq(SmErpAuxiliaryCodeEntity::getSpuId, spu.getId()) + .eq(SmErpAuxiliaryCodeEntity::getBarCode, auxiliaryBarcode); + SmErpAuxiliaryCodeEntity existingBarcode = smErpAuxiliaryCodeService.getOne(existingBarcodeWrapper); + + if (existingBarcode != null) { + // 辅助条码已存在,更新关联的包装单位ID + existingBarcode.setUnitId(unit.getId()); + smErpAuxiliaryCodeService.updateById(existingBarcode); + } else { + SmErpAuxiliaryCodeEntity auxiliaryCode = new SmErpAuxiliaryCodeEntity(); + auxiliaryCode.setSpuId(spu.getId()); + auxiliaryCode.setBarCode(auxiliaryBarcode); + auxiliaryCode.setUnitId(unit.getId()); + smErpAuxiliaryCodeService.save(auxiliaryCode); + } + } + + // 6. 关键逻辑:库存数量转换和汇总 + // 将包装单位的库存乘以内装数,然后累加到商品总库存 + Double unitStock = dto.getStock() != null ? dto.getStock() : 0.0; + Double unitActualStock = unitStock * dto.getPackageNum(); + + // 7. 更新口味库存(如果有口味) + if (tasteId != null) { + // 累加同一口味的库存 + tasteStockMap.merge(dto.getTaste(), unitActualStock, Double::sum); + } + + // 8. 累加到商品总库存 + totalSpuStock += unitActualStock; + + } catch (Exception e) { + errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(), + Arrays.asList("处理失败: " + e.getMessage()))); + continue; + } + } + + // 第二轮:更新口味库存和商品总库存 + if (spu != null && !units.isEmpty()) { + try { + // 更新口味库存 + for (Map.Entry tasteEntry : tasteStockMap.entrySet()) { + String tasteName = tasteEntry.getKey(); + Double totalTasteStock = tasteEntry.getValue(); + + LambdaQueryWrapper tasteWrapper = new LambdaQueryWrapper<>(); + tasteWrapper.eq(SmErpTasteStockEntity::getSpuId, spu.getId()) + .eq(SmErpTasteStockEntity::getTasteName, tasteName); + SmErpTasteStockEntity tasteStock = smErpTasteStockMapper.selectOne(tasteWrapper); + + if (tasteStock != null) { + tasteStock.setStock(totalTasteStock); + smErpTasteStockMapper.updateById(tasteStock); + } + } + + // 更新商品总库存 + LambdaQueryWrapper existingStockWrapper = new LambdaQueryWrapper<>(); + existingStockWrapper.eq(SmErpStockEntity::getErpSpuId, spu.getId()); + SmErpStockEntity existingStock = smErpStockService.getOne(existingStockWrapper); + + if (existingStock != null) { + existingStock.setInventoryUpperLimit(1000); // 默认值 + existingStock.setInventoryLowerLimit(10); // 默认值 + existingStock.setBaseStock(totalSpuStock); + existingStock.setCurrentStock(totalSpuStock); + smErpStockService.updateById(existingStock); + } else { + SmErpStockEntity stock = new SmErpStockEntity(); + stock.setErpSpuId(spu.getId()); + stock.setInventoryUpperLimit(1000); + stock.setInventoryLowerLimit(10); + stock.setBaseStock(totalSpuStock); + stock.setCurrentStock(totalSpuStock); + smErpStockService.save(stock); + } + + successList.add(spu); + successCount++; + + } catch (Exception e) { + errorList.add(createErrorInfo(1, productCode, + Arrays.asList("库存更新失败: " + e.getMessage()))); + } + } + } + + return buildImportResult(totalCount, successCount, errorList); +} + } \ No newline at end of file diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpStockServiceImpl.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpStockServiceImpl.java index 364de448e..23f97b80d 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpStockServiceImpl.java +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpStockServiceImpl.java @@ -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 implements SmErpStockService { private final SmErpSpuMapper smErpSpuMapper; + + private final SmErpTasteStockService smErpTasteStockService; + + private final SmErpUnitService smErpUnitService; @Override @@ -46,6 +53,23 @@ public class SmErpStockServiceImpl extends ServiceImpl smErpStockEntityLambdaQueryWrapper = new LambdaQueryWrapper(); smErpStockEntityLambdaQueryWrapper.eq(SmErpStockEntity::getErpSpuId,item.getId()); @@ -63,6 +87,5 @@ public class SmErpStockServiceImpl extends ServiceImpl 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 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 updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(SmErpTasteStockEntity::getId, tasteId) + .set(SmErpTasteStockEntity::getStock, newStock); + + return this.update(updateWrapper); + } } \ No newline at end of file