From af69388cbcd26a9a316505c347b332075054d7d4 Mon Sep 17 00:00:00 2001 From: ck-chenkang Date: Tue, 23 Jun 2026 15:18:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=A0=B7=E5=93=81=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E5=92=8C=E5=87=BA=E5=85=A5=E5=BA=93=E6=98=8E=E7=BB=86=E5=B1=95?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/bitwms/vo/BitWmsInboundReqVO.java | 7 ++ .../vo/record/ErpStockRecordPageReqVO.java | 9 ++ .../stock/vo/stock/ErpStockPageReqVO.java | 6 + .../erp/dal/mysql/stock/ErpStockMapper.java | 15 ++- .../dal/mysql/stock/ErpStockRecordMapper.java | 46 +++++++ .../erp/service/bitwms/BitWmsServiceImpl.java | 48 +++++++- .../service/stock/ErpStockInServiceImpl.java | 7 +- .../service/stock/ErpStockOutServiceImpl.java | 4 + .../service/bitwms/BitWmsServiceImplTest.java | 114 ++++++++++++++++++ 9 files changed, 249 insertions(+), 7 deletions(-) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/bitwms/vo/BitWmsInboundReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/bitwms/vo/BitWmsInboundReqVO.java index 1833c891b..a0b0c3dd8 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/bitwms/vo/BitWmsInboundReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/bitwms/vo/BitWmsInboundReqVO.java @@ -22,11 +22,18 @@ public class BitWmsInboundReqVO { @Schema(description = "库区ID", example = "30") private Long areaId; + @Schema(description = "库位ID", example = "40") + private Long locationId; + @Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @NotNull(message = "入库数量不能为空") @DecimalMin(value = "0.000001", message = "入库数量必须大于 0") private BigDecimal count; + @Schema(description = "单位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "单位不能为空") + private Long unitId; + @Schema(description = "供应商ID", example = "1001") private Long supplierId; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java index 6deea7e57..0d0d6e332 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java @@ -31,6 +31,15 @@ public class ErpStockRecordPageReqVO extends PageParam { @Schema(description = "业务类型", example = "10") private Integer bizType; + @Schema(description = "是否样品", example = "true") + private Boolean isSample; + + @Schema(description = "业务单位", example = "BIT") + private String bizUnit; + + @Schema(description = "是否仅查询 BIT 样品 WMS 流水", example = "true") + private Boolean bitWmsOnly; + @Schema(description = "业务单号", example = "Z110") private String bizNo; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java index ffb904ea0..77212ebd6 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java @@ -27,6 +27,12 @@ public class ErpStockPageReqVO extends PageParam { @Schema(description = "产品分类类型", example = "1") private Integer categoryType; + @Schema(description = "是否样品", example = "true") + private Boolean isSample; + + @Schema(description = "业务单位", example = "BIT") + private String bizUnit; + @Schema(description = "id集合导出用") private String ids; } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java index b353be054..15011e5d5 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java @@ -48,11 +48,24 @@ public interface ErpStockMapper extends BaseMapperX { erpStockDOLambdaQueryWrapperX.in(ErpStockDO::getId, idList); } - + appendProductScope(erpStockDOLambdaQueryWrapperX, reqVO.getIsSample(), reqVO.getBizUnit()); return selectPage(reqVO,erpStockDOLambdaQueryWrapperX); } + static void appendProductScope(LambdaQueryWrapperX query, Boolean isSample, String bizUnit) { + if (isSample != null && StringUtils.isNotBlank(bizUnit)) { + query.apply("EXISTS (SELECT 1 FROM erp_product ep WHERE ep.id = product_id AND ep.deleted = 0 AND ep.is_sample = {0} AND ep.biz_unit = {1})", + isSample, bizUnit); + } else if (isSample != null) { + query.apply("EXISTS (SELECT 1 FROM erp_product ep WHERE ep.id = product_id AND ep.deleted = 0 AND ep.is_sample = {0})", + isSample); + } else if (StringUtils.isNotBlank(bizUnit)) { + query.apply("EXISTS (SELECT 1 FROM erp_product ep WHERE ep.id = product_id AND ep.deleted = 0 AND ep.biz_unit = {0})", + bizUnit); + } + } + default ErpStockDO selectByProductIdAndWarehouseId(Long productId, Long warehouseId) { return selectByProductIdAndWarehouseIdAndAreaId(productId, warehouseId, null); } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java index f69841eff..38b81cf79 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; import com.alibaba.excel.util.StringUtils; import org.apache.ibatis.annotations.Mapper; @@ -23,6 +24,10 @@ import java.util.stream.Collectors; @Mapper public interface ErpStockRecordMapper extends BaseMapperX { + String BIT_BIZ_UNIT = "BIT"; + String SAMPLE_IN_TYPE = "样品入库"; + String SAMPLE_OUT_TYPE = "样品出库"; + default PageResult selectPage(ErpStockRecordPageReqVO reqVO) { LambdaQueryWrapperX erpStockRecordDOLambdaQueryWrapperX = new LambdaQueryWrapperX() @@ -46,9 +51,50 @@ public interface ErpStockRecordMapper extends BaseMapperX { erpStockRecordDOLambdaQueryWrapperX.in(ErpStockRecordDO::getId, idList); } + if (Boolean.TRUE.equals(reqVO.getBitWmsOnly())) { + appendProductScope(erpStockRecordDOLambdaQueryWrapperX, true, BIT_BIZ_UNIT); + appendBitWmsRecordScope(erpStockRecordDOLambdaQueryWrapperX); + } else { + appendProductScope(erpStockRecordDOLambdaQueryWrapperX, reqVO.getIsSample(), reqVO.getBizUnit()); + } return selectPage(reqVO,erpStockRecordDOLambdaQueryWrapperX); } + + static void appendProductScope(LambdaQueryWrapperX query, Boolean isSample, String bizUnit) { + if (isSample != null && StringUtils.isNotBlank(bizUnit)) { + query.apply("EXISTS (SELECT 1 FROM erp_product ep WHERE ep.id = product_id AND ep.deleted = 0 AND ep.is_sample = {0} AND ep.biz_unit = {1})", + isSample, bizUnit); + } else if (isSample != null) { + query.apply("EXISTS (SELECT 1 FROM erp_product ep WHERE ep.id = product_id AND ep.deleted = 0 AND ep.is_sample = {0})", + isSample); + } else if (StringUtils.isNotBlank(bizUnit)) { + query.apply("EXISTS (SELECT 1 FROM erp_product ep WHERE ep.id = product_id AND ep.deleted = 0 AND ep.biz_unit = {0})", + bizUnit); + } + } + + static void appendBitWmsRecordScope(LambdaQueryWrapperX query) { + query.apply("(" + + "((biz_type IS NULL OR biz_type IN ({0}, {1})) AND EXISTS (" + + "SELECT 1 FROM erp_stock_in si WHERE si.id = biz_id AND si.no = biz_no AND si.deleted = 0 AND si.in_type = {2}))" + + " OR ((biz_type IS NULL OR biz_type IN ({3}, {4})) AND EXISTS (" + + "SELECT 1 FROM erp_stock_out so WHERE so.id = biz_id AND so.no = biz_no AND so.deleted = 0 AND so.out_type = {5}))" + + " OR (biz_type IN ({6}, {7}, {8}, {9}) AND EXISTS (" + + "SELECT 1 FROM erp_stock_move sm WHERE sm.id = biz_id AND sm.no = biz_no AND sm.deleted = 0))" + + ")", + ErpStockRecordBizTypeEnum.OTHER_IN.getType(), + ErpStockRecordBizTypeEnum.OTHER_IN_CANCEL.getType(), + SAMPLE_IN_TYPE, + ErpStockRecordBizTypeEnum.OTHER_OUT.getType(), + ErpStockRecordBizTypeEnum.OTHER_OUT_CANCEL.getType(), + SAMPLE_OUT_TYPE, + ErpStockRecordBizTypeEnum.MOVE_IN.getType(), + ErpStockRecordBizTypeEnum.MOVE_IN_CANCEL.getType(), + ErpStockRecordBizTypeEnum.MOVE_OUT.getType(), + ErpStockRecordBizTypeEnum.MOVE_OUT_CANCEL.getType()); + } + default LocalDateTime selectLatestRecordTime(Long productId, Long warehouseId, Long areaId, boolean inbound) { ErpStockRecordDO record = selectOne(new LambdaQueryWrapperX() .eq(ErpStockRecordDO::getProductId, productId) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImpl.java index e00d1d099..321bf4bcf 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImpl.java @@ -10,8 +10,10 @@ import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsMoveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsOutboundReqVO; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsScanRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInAuditReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutAuditReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVOItem; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; @@ -40,6 +42,7 @@ import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_CODE_NOT_EXISTS; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_UNIT_NOT_EXISTS; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE2; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_LOCATION_NOT_EXISTS; @@ -81,22 +84,34 @@ public class BitWmsServiceImpl implements BitWmsService { @Transactional(rollbackFor = Exception.class) public Long inbound(BitWmsInboundReqVO reqVO) { ErpProductRespVO product = validateBitSample(reqVO.getProductId()); + validateInboundUnit(reqVO, product); + WarehouseLocationDO location = resolveInboundLocation(reqVO); + Long warehouseId = location != null ? location.getWarehouseId() : reqVO.getWarehouseId(); + Long areaId = location != null ? location.getAreaId() : reqVO.getAreaId(); + ErpStockInSaveReqVO stockIn = new ErpStockInSaveReqVO(); stockIn.setSupplierId(reqVO.getSupplierId()); stockIn.setInTime(LocalDateTime.now()); stockIn.setInType(SAMPLE_IN_TYPE); stockIn.setRemark(reqVO.getRemark()); - stockIn.setWarehouseId(reqVO.getWarehouseId()); + stockIn.setWarehouseId(warehouseId); ErpStockInSaveReqVO.Item item = new ErpStockInSaveReqVO.Item(); item.setProductId(reqVO.getProductId()); - item.setWarehouseId(reqVO.getWarehouseId()); - item.setAreaId(reqVO.getAreaId()); + item.setWarehouseId(warehouseId); + item.setAreaId(areaId); item.setCount(reqVO.getCount()); item.setProductPrice(product.getPurchasePrice() != null ? product.getPurchasePrice() : BigDecimal.ZERO); + item.setRelateTask(false); item.setRemark(reqVO.getRemark()); stockIn.setItems(Collections.singletonList(item)); - return stockInService.createStockIn(stockIn); + Long id = stockInService.createStockIn(stockIn); + ErpStockInAuditReqVO auditReqVO = new ErpStockInAuditReqVO(); + auditReqVO.setId(id); + auditReqVO.setStatus(ErpAuditStatus.APPROVE.getStatus()); + auditReqVO.setRemark(reqVO.getRemark() != null ? reqVO.getRemark() : "样品入库自动入库"); + stockInService.auditStockIn(auditReqVO); + return id; } @Override @@ -118,7 +133,13 @@ public class BitWmsServiceImpl implements BitWmsService { item.setProductPrice(product.getPurchasePrice() != null ? product.getPurchasePrice() : BigDecimal.ZERO); item.setRemark(reqVO.getRemark()); stockOut.setItems(Collections.singletonList(item)); - return stockOutService.createStockOut(stockOut); + Long id = stockOutService.createStockOut(stockOut); + ErpStockOutAuditReqVO auditReqVO = new ErpStockOutAuditReqVO(); + auditReqVO.setId(id); + auditReqVO.setStatus(ErpAuditStatus.APPROVE.getStatus()); + auditReqVO.setRemark(reqVO.getRemark() != null ? reqVO.getRemark() : "样品出库自动出库"); + stockOutService.auditStockOut(auditReqVO); + return id; } @Override @@ -213,6 +234,23 @@ public class BitWmsServiceImpl implements BitWmsService { return product; } + private void validateInboundUnit(BitWmsInboundReqVO reqVO, ErpProductRespVO product) { + if (reqVO.getUnitId() == null || product.getUnitId() == null || !reqVO.getUnitId().equals(product.getUnitId())) { + throw exception(PRODUCT_UNIT_NOT_EXISTS); + } + } + + private WarehouseLocationDO resolveInboundLocation(BitWmsInboundReqVO reqVO) { + if (reqVO.getLocationId() == null) { + return null; + } + WarehouseLocationDO location = warehouseLocationMapper.selectById(reqVO.getLocationId()); + if (location == null) { + throw exception(WAREHOUSE_LOCATION_NOT_EXISTS); + } + return location; + } + private void validateStockEnough(Long productId, Long warehouseId, Long areaId, BigDecimal count) { ErpStockDO stock = stockService.getStock(productId, warehouseId, areaId); BigDecimal currentCount = stock != null && stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index 34f8feb6c..abc5e605d 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -420,8 +420,13 @@ public class ErpStockInServiceImpl implements ErpStockInService { if (bizType != null) { return bizType; } - return approve ? ErpStockRecordBizTypeEnum.getTypeByName(inType) + Integer recordBizType = approve ? ErpStockRecordBizTypeEnum.getTypeByName(inType) : ErpStockRecordBizTypeEnum.getTypeByName(inType, 10); + if (recordBizType != null) { + return recordBizType; + } + return approve ? ErpStockRecordBizTypeEnum.OTHER_IN.getType() + : ErpStockRecordBizTypeEnum.OTHER_IN_CANCEL.getType(); } private boolean itemNeedUpdateMoldStatus(MoldBrandDO moldDO) { diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java index 2b097c11d..5694d680e 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java @@ -420,6 +420,10 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { Integer recordBizType = bizType != null ? bizType : (approve ? ErpStockRecordBizTypeEnum.getTypeByName(stockOut.getOutType()) : ErpStockRecordBizTypeEnum.getTypeByName(stockOut.getOutType(), 10)); + if (recordBizType == null) { + recordBizType = approve ? ErpStockRecordBizTypeEnum.OTHER_OUT.getType() + : ErpStockRecordBizTypeEnum.OTHER_OUT_CANCEL.getType(); + } stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( stockOutItem.getProductId(), product.getCategoryId(), product.getCategoryType(), stockOutItem.getWarehouseId(), stockOutItem.getAreaId(), stockOutItem.getAreaName(), count, diff --git a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImplTest.java b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImplTest.java index 9f6807ab7..53874b783 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImplTest.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImplTest.java @@ -10,15 +10,20 @@ import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLabelRespVO; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsMoveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsOutboundReqVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInAuditReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutAuditReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; import cn.iocoder.yudao.module.erp.dal.mysql.warehouselocation.WarehouseLocationMapper; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.warehouselocation.WarehouseLocationDO; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockInService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockMoveService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockOutService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -29,6 +34,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.math.BigDecimal; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_UNIT_NOT_EXISTS; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; @@ -54,6 +60,8 @@ class BitWmsServiceImplTest { @Mock private ErpStockInService stockInService; @Mock + private ErpStockOutService stockOutService; + @Mock private ErpStockMoveService stockMoveService; @Mock private ErpStockService stockService; @@ -69,6 +77,7 @@ class BitWmsServiceImplTest { reqVO.setWarehouseId(20L); reqVO.setAreaId(30L); reqVO.setCount(new BigDecimal("2")); + reqVO.setUnitId(5L); reqVO.setRemark("first shelf"); ErpProductRespVO product = buildBitSampleProduct(); @@ -87,6 +96,74 @@ class BitWmsServiceImplTest { assertEquals(20L, stockIn.getItems().get(0).getWarehouseId()); assertEquals(30L, stockIn.getItems().get(0).getAreaId()); assertEquals(new BigDecimal("2"), stockIn.getItems().get(0).getCount()); + assertEquals(false, stockIn.getItems().get(0).getRelateTask()); + + ArgumentCaptor auditCaptor = ArgumentCaptor.forClass(ErpStockInAuditReqVO.class); + verify(stockInService).auditStockIn(auditCaptor.capture()); + assertEquals(100L, auditCaptor.getValue().getId()); + assertEquals(ErpAuditStatus.APPROVE.getStatus(), auditCaptor.getValue().getStatus()); + assertEquals("first shelf", auditCaptor.getValue().getRemark()); + } + + @Test + void inbound_whenLocationSelected_usesLocationWarehouseAndArea() { + BitWmsInboundReqVO reqVO = new BitWmsInboundReqVO(); + reqVO.setProductId(10L); + reqVO.setWarehouseId(999L); + reqVO.setAreaId(998L); + reqVO.setLocationId(88L); + reqVO.setCount(new BigDecimal("2")); + reqVO.setUnitId(5L); + + when(productService.getProduct(10L)).thenReturn(buildBitSampleProduct()); + when(warehouseLocationMapper.selectById(88L)).thenReturn(new WarehouseLocationDO() + .setId(88L).setWarehouseId(20L).setAreaId(30L)); + when(stockInService.createStockIn(org.mockito.ArgumentMatchers.any(ErpStockInSaveReqVO.class))).thenReturn(100L); + + bitWmsService.inbound(reqVO); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ErpStockInSaveReqVO.class); + verify(stockInService).createStockIn(captor.capture()); + ErpStockInSaveReqVO stockIn = captor.getValue(); + assertEquals(20L, stockIn.getWarehouseId()); + assertEquals(20L, stockIn.getItems().get(0).getWarehouseId()); + assertEquals(30L, stockIn.getItems().get(0).getAreaId()); + assertEquals(false, stockIn.getItems().get(0).getRelateTask()); + } + + @Test + void inbound_whenRemarkBlank_autoApprovesWithDefaultRemark() { + BitWmsInboundReqVO reqVO = new BitWmsInboundReqVO(); + reqVO.setProductId(10L); + reqVO.setWarehouseId(20L); + reqVO.setAreaId(30L); + reqVO.setCount(new BigDecimal("2")); + reqVO.setUnitId(5L); + + when(productService.getProduct(10L)).thenReturn(buildBitSampleProduct()); + when(stockInService.createStockIn(org.mockito.ArgumentMatchers.any(ErpStockInSaveReqVO.class))).thenReturn(100L); + + bitWmsService.inbound(reqVO); + + ArgumentCaptor auditCaptor = ArgumentCaptor.forClass(ErpStockInAuditReqVO.class); + verify(stockInService).auditStockIn(auditCaptor.capture()); + assertEquals(100L, auditCaptor.getValue().getId()); + assertEquals(ErpAuditStatus.APPROVE.getStatus(), auditCaptor.getValue().getStatus()); + assertEquals("样品入库自动入库", auditCaptor.getValue().getRemark()); + } + + @Test + void inbound_whenUnitDoesNotMatchSampleUnit_throwsException() { + BitWmsInboundReqVO reqVO = new BitWmsInboundReqVO(); + reqVO.setProductId(10L); + reqVO.setWarehouseId(20L); + reqVO.setAreaId(30L); + reqVO.setCount(new BigDecimal("2")); + reqVO.setUnitId(99L); + + when(productService.getProduct(10L)).thenReturn(buildBitSampleProduct()); + + AssertUtils.assertServiceException(() -> bitWmsService.inbound(reqVO), PRODUCT_UNIT_NOT_EXISTS); } @Test @@ -104,6 +181,41 @@ class BitWmsServiceImplTest { AssertUtils.assertServiceException(() -> bitWmsService.outbound(reqVO), STOCK_COUNT_NEGATIVE2, 10L, 20L); } + @Test + void outbound_createsSampleStockOutAndAutoApproves() { + BitWmsOutboundReqVO reqVO = new BitWmsOutboundReqVO(); + reqVO.setProductId(10L); + reqVO.setWarehouseId(20L); + reqVO.setAreaId(30L); + reqVO.setCount(new BigDecimal("1")); + reqVO.setOutReason("TEST"); + reqVO.setRemark("out remark"); + + when(productService.getProduct(10L)).thenReturn(buildBitSampleProduct()); + when(stockService.getStock(10L, 20L, 30L)).thenReturn(new ErpStockDO().setCount(new BigDecimal("2"))); + when(stockOutService.createStockOut(org.mockito.ArgumentMatchers.any(ErpStockOutSaveReqVO.class))).thenReturn(200L); + + Long id = bitWmsService.outbound(reqVO); + + assertEquals(200L, id); + ArgumentCaptor stockOutCaptor = ArgumentCaptor.forClass(ErpStockOutSaveReqVO.class); + verify(stockOutService).createStockOut(stockOutCaptor.capture()); + ErpStockOutSaveReqVO stockOut = stockOutCaptor.getValue(); + assertEquals("样品出库", stockOut.getOutType()); + assertEquals("出库原因:TEST;out remark", stockOut.getRemark()); + assertEquals(1, stockOut.getItems().size()); + assertEquals(10L, stockOut.getItems().get(0).getProductId()); + assertEquals(20L, stockOut.getItems().get(0).getWarehouseId()); + assertEquals(30L, stockOut.getItems().get(0).getAreaId()); + assertEquals(new BigDecimal("1"), stockOut.getItems().get(0).getCount()); + + ArgumentCaptor auditCaptor = ArgumentCaptor.forClass(ErpStockOutAuditReqVO.class); + verify(stockOutService).auditStockOut(auditCaptor.capture()); + assertEquals(200L, auditCaptor.getValue().getId()); + assertEquals(ErpAuditStatus.APPROVE.getStatus(), auditCaptor.getValue().getStatus()); + assertEquals("out remark", auditCaptor.getValue().getRemark()); + } + @Test void move_keepsTotalStockAndChangesLocation() { BitWmsMoveReqVO reqVO = new BitWmsMoveReqVO(); @@ -191,6 +303,8 @@ class BitWmsServiceImplTest { product.setIsSample(true); product.setBizUnit("BIT"); product.setCategoryId(50L); + product.setUnitId(5L); + product.setUnitName("个"); return product; } }