PDA 扫码内容 类型-ID 格式适配

besure_bit
ck-chenkang 2 weeks ago
parent af69388cbc
commit 15b2bc983b

@ -0,0 +1,48 @@
-- BIT 样品仓库位库存台账
CREATE TABLE IF NOT EXISTS `erp_bit_wms_location_stock` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`product_id` bigint NOT NULL COMMENT '样品产品ID',
`warehouse_id` bigint NOT NULL COMMENT '仓库ID',
`area_id` bigint NULL COMMENT '库区ID',
`location_id` bigint NOT NULL COMMENT '库位ID',
`count` decimal(24, 6) NOT NULL DEFAULT 0.000000 COMMENT '当前库存数量',
`unit_id` bigint NULL COMMENT '单位ID',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uk_product_location` (`product_id`, `location_id`, `deleted`, `tenant_id`) USING BTREE,
KEY `idx_location` (`location_id`) USING BTREE,
KEY `idx_warehouse_area` (`warehouse_id`, `area_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BIT 样品库位库存';
CREATE TABLE IF NOT EXISTS `erp_bit_wms_location_stock_record` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`product_id` bigint NOT NULL COMMENT '样品产品ID',
`warehouse_id` bigint NOT NULL COMMENT '仓库ID',
`area_id` bigint NULL COMMENT '库区ID',
`location_id` bigint NOT NULL COMMENT '库位ID',
`count` decimal(24, 6) NOT NULL COMMENT '变动数量',
`total_count` decimal(24, 6) NOT NULL COMMENT '变动后库位结存',
`unit_id` bigint NULL COMMENT '单位ID',
`biz_direction` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '业务方向',
`biz_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '业务类型',
`biz_id` bigint NULL COMMENT '业务单ID',
`biz_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '业务单号',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '备注',
`record_time` datetime NOT NULL COMMENT '操作时间',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_product_location` (`product_id`, `location_id`) USING BTREE,
KEY `idx_biz_no` (`biz_no`) USING BTREE,
KEY `idx_record_time` (`record_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BIT 样品库位库存流水';

@ -1,8 +1,13 @@
package cn.iocoder.yudao.module.erp.controller.admin.bitwms;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsInboundReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLabelRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRespVO;
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;
@ -20,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.math.BigDecimal;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -60,6 +66,30 @@ public class BitWmsController {
return success(bitWmsService.scan(code));
}
@GetMapping("/location-stock/page")
@Operation(summary = "获得 BIT 样品库位库存分页")
@PreAuthorize("@ss.hasPermission('erp:bit-wms-stock:query')")
public CommonResult<PageResult<BitWmsLocationStockRespVO>> getLocationStockPage(
@Valid BitWmsLocationStockPageReqVO pageReqVO) {
return success(bitWmsService.getLocationStockPage(pageReqVO));
}
@GetMapping("/location-stock/count")
@Operation(summary = "获得 BIT 样品当前库位库存")
@PreAuthorize("@ss.hasPermission('erp:bit-wms-stock:query')")
public CommonResult<BigDecimal> getLocationStockCount(@RequestParam("productId") Long productId,
@RequestParam("locationId") Long locationId) {
return success(bitWmsService.getLocationStockCount(productId, locationId));
}
@GetMapping("/location-stock-record/page")
@Operation(summary = "获得 BIT 样品库位流水分页")
@PreAuthorize("@ss.hasPermission('erp:bit-wms-record:query')")
public CommonResult<PageResult<BitWmsLocationStockRecordRespVO>> getLocationStockRecordPage(
@Valid BitWmsLocationStockRecordPageReqVO pageReqVO) {
return success(bitWmsService.getLocationStockRecordPage(pageReqVO));
}
@GetMapping("/sample-label")
@Operation(summary = "获得样品标签打印数据")
@PreAuthorize("@ss.hasPermission('erp:bit-wms-sample:print')")

@ -15,14 +15,14 @@ public class BitWmsInboundReqVO {
@NotNull(message = "样品产品ID不能为空")
private Long productId;
@Schema(description = "仓库ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
@NotNull(message = "仓库ID不能为空")
@Schema(description = "仓库ID", example = "20")
private Long warehouseId;
@Schema(description = "库区ID", example = "30")
private Long areaId;
@Schema(description = "库位ID", example = "40")
@Schema(description = "库位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "40")
@NotNull(message = "库位不能为空")
private Long locationId;
@Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - BIT 样品库位库存分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BitWmsLocationStockPageReqVO extends PageParam {
@Schema(description = "样品产品ID", example = "10")
private Long productId;
@Schema(description = "仓库ID", example = "20")
private Long warehouseId;
@Schema(description = "库区ID", example = "30")
private Long areaId;
@Schema(description = "库位ID", example = "40")
private Long locationId;
}

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - BIT 样品库位流水分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BitWmsLocationStockRecordPageReqVO extends PageParam {
@Schema(description = "样品产品ID", example = "10")
private Long productId;
@Schema(description = "仓库ID", example = "20")
private Long warehouseId;
@Schema(description = "库区ID", example = "30")
private Long areaId;
@Schema(description = "库位ID", example = "40")
private Long locationId;
@Schema(description = "业务单号", example = "QTRK20260623001")
private String bizNo;
}

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - BIT 样品库位流水 Response VO")
@Data
public class BitWmsLocationStockRecordRespVO {
private Long id;
private Long productId;
private String productName;
private String barCode;
private Long warehouseId;
private String warehouseName;
private Long areaId;
private String areaName;
private Long locationId;
private String locationCode;
private String locationName;
private BigDecimal count;
private BigDecimal totalCount;
private Long unitId;
private String unitName;
private String bizDirection;
private String bizType;
private Long bizId;
private String bizNo;
private String remark;
private String creator;
private String creatorName;
private LocalDateTime recordTime;
private LocalDateTime createTime;
}

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - BIT 样品库位库存 Response VO")
@Data
public class BitWmsLocationStockRespVO {
private Long id;
private Long productId;
private String productName;
private String barCode;
private String sampleCategory;
private String customerName;
private Long warehouseId;
private String warehouseName;
private Long areaId;
private String areaName;
private Long locationId;
private String locationCode;
private String locationName;
private BigDecimal count;
private Long unitId;
private String unitName;
}

@ -15,15 +15,21 @@ public class BitWmsMoveReqVO {
@NotNull(message = "样品产品ID不能为空")
private Long productId;
@Schema(description = "调出仓库ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
@NotNull(message = "调出仓库ID不能为空")
@Schema(description = "调出库位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "40")
@NotNull(message = "调出库位不能为空")
private Long fromLocationId;
@Schema(description = "调入库位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "41")
@NotNull(message = "调入库位不能为空")
private Long toLocationId;
@Schema(description = "调出仓库ID", example = "20")
private Long fromWarehouseId;
@Schema(description = "调出库区ID", example = "30")
private Long fromAreaId;
@Schema(description = "调入仓库ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
@NotNull(message = "调入仓库ID不能为空")
@Schema(description = "调入仓库ID", example = "20")
private Long toWarehouseId;
@Schema(description = "调入库区ID", example = "31")

@ -16,13 +16,16 @@ public class BitWmsOutboundReqVO {
@NotNull(message = "样品产品ID不能为空")
private Long productId;
@Schema(description = "仓库ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
@NotNull(message = "仓库ID不能为空")
@Schema(description = "仓库ID", example = "20")
private Long warehouseId;
@Schema(description = "库区ID", example = "30")
private Long areaId;
@Schema(description = "库位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "40")
@NotNull(message = "库位不能为空")
private Long locationId;
@Schema(description = "出库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "出库数量不能为空")
@DecimalMin(value = "0.000001", message = "出库数量必须大于 0")

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.bitwms;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.math.BigDecimal;
/**
* BIT DO
*/
@TableName("erp_bit_wms_location_stock")
@KeySequence("erp_bit_wms_location_stock_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BitWmsLocationStockDO extends BaseDO {
@TableId
private Long id;
private Long productId;
private Long warehouseId;
private Long areaId;
private Long locationId;
private BigDecimal count;
private Long unitId;
}

@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.bitwms;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* BIT DO
*/
@TableName("erp_bit_wms_location_stock_record")
@KeySequence("erp_bit_wms_location_stock_record_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BitWmsLocationStockRecordDO extends BaseDO {
@TableId
private Long id;
private Long productId;
private Long warehouseId;
private Long areaId;
private Long locationId;
private BigDecimal count;
private BigDecimal totalCount;
private Long unitId;
private String bizDirection;
private String bizType;
private Long bizId;
private String bizNo;
private String remark;
private LocalDateTime recordTime;
}

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.erp.dal.mysql.bitwms;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.bitwms.BitWmsLocationStockDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.math.BigDecimal;
@Mapper
public interface BitWmsLocationStockMapper extends BaseMapperX<BitWmsLocationStockDO> {
default PageResult<BitWmsLocationStockDO> selectPage(BitWmsLocationStockPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BitWmsLocationStockDO>()
.eqIfPresent(BitWmsLocationStockDO::getProductId, reqVO.getProductId())
.eqIfPresent(BitWmsLocationStockDO::getWarehouseId, reqVO.getWarehouseId())
.eqIfPresent(BitWmsLocationStockDO::getAreaId, reqVO.getAreaId())
.eqIfPresent(BitWmsLocationStockDO::getLocationId, reqVO.getLocationId())
.ne(BitWmsLocationStockDO::getCount, BigDecimal.ZERO)
.orderByDesc(BitWmsLocationStockDO::getId));
}
default BitWmsLocationStockDO selectByProductIdAndLocationId(Long productId, Long locationId) {
return selectOne(new LambdaQueryWrapperX<BitWmsLocationStockDO>()
.eq(BitWmsLocationStockDO::getProductId, productId)
.eq(BitWmsLocationStockDO::getLocationId, locationId));
}
default int updateCountIncrement(Long id, BigDecimal count, boolean negativeEnable) {
if (count == null || count.compareTo(BigDecimal.ZERO) == 0) {
return 0;
}
LambdaUpdateWrapper<BitWmsLocationStockDO> updateWrapper = new LambdaUpdateWrapper<BitWmsLocationStockDO>()
.eq(BitWmsLocationStockDO::getId, id);
if (count.compareTo(BigDecimal.ZERO) > 0) {
updateWrapper.setSql("count = count + " + count);
} else {
if (!negativeEnable) {
updateWrapper.ge(BitWmsLocationStockDO::getCount, count.abs());
}
updateWrapper.setSql("count = count - " + count.abs());
}
return update(null, updateWrapper);
}
}

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.erp.dal.mysql.bitwms;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.bitwms.BitWmsLocationStockRecordDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BitWmsLocationStockRecordMapper extends BaseMapperX<BitWmsLocationStockRecordDO> {
default PageResult<BitWmsLocationStockRecordDO> selectPage(BitWmsLocationStockRecordPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BitWmsLocationStockRecordDO>()
.eqIfPresent(BitWmsLocationStockRecordDO::getProductId, reqVO.getProductId())
.eqIfPresent(BitWmsLocationStockRecordDO::getWarehouseId, reqVO.getWarehouseId())
.eqIfPresent(BitWmsLocationStockRecordDO::getAreaId, reqVO.getAreaId())
.eqIfPresent(BitWmsLocationStockRecordDO::getLocationId, reqVO.getLocationId())
.likeIfPresent(BitWmsLocationStockRecordDO::getBizNo, reqVO.getBizNo())
.orderByDesc(BitWmsLocationStockRecordDO::getId));
}
}

@ -1,11 +1,17 @@
package cn.iocoder.yudao.module.erp.service.bitwms;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsInboundReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLabelRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRespVO;
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 java.math.BigDecimal;
import javax.validation.Valid;
public interface BitWmsService {
@ -18,6 +24,12 @@ public interface BitWmsService {
BitWmsScanRespVO scan(String code);
PageResult<BitWmsLocationStockRespVO> getLocationStockPage(@Valid BitWmsLocationStockPageReqVO pageReqVO);
PageResult<BitWmsLocationStockRecordRespVO> getLocationStockRecordPage(@Valid BitWmsLocationStockRecordPageReqVO pageReqVO);
BigDecimal getLocationStockCount(Long productId, Long locationId);
BitWmsLabelRespVO getSampleLabel(Long productId);
BitWmsLabelRespVO getLocationLabel(Long locationId);

@ -1,11 +1,18 @@
package cn.iocoder.yudao.module.erp.service.bitwms;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.common.enums.CodeTypeEnum;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsInboundReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLabelRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRespVO;
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;
@ -16,9 +23,17 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSa
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.bitwms.BitWmsLocationStockDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.bitwms.BitWmsLocationStockRecordDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.warehousearea.WarehouseAreaDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.warehouselocation.WarehouseLocationDO;
import cn.iocoder.yudao.module.erp.dal.mysql.bitwms.BitWmsLocationStockMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.bitwms.BitWmsLocationStockRecordMapper;
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.enums.ErpAuditStatus;
@ -26,7 +41,10 @@ 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 cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService;
import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@ -36,8 +54,14 @@ import java.math.BigDecimal;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_CODE_NOT_EXISTS;
@ -60,6 +84,7 @@ public class BitWmsServiceImpl implements BitWmsService {
private static final String BIT_WAREHOUSE_LOCATION_CODE_RULE = "BIT_WAREHOUSE_LOCATION_CODE";
private static final int SAMPLE_PRINT_TEMPLATE_TYPE = 7;
private static final int LOCATION_PRINT_TEMPLATE_TYPE = 8;
private static final Pattern QRCODE_BIZ_KEY_PATTERN = Pattern.compile("^(.+)[-_](\\d+)$");
@Resource
private ErpProductService productService;
@ -74,11 +99,19 @@ public class BitWmsServiceImpl implements BitWmsService {
@Resource
private ErpStockMoveService stockMoveService;
@Resource
private ErpStockService stockService;
private ErpWarehouseService warehouseService;
@Resource
private WarehouseAreaService warehouseAreaService;
@Resource
private BitWmsLocationStockMapper locationStockMapper;
@Resource
private BitWmsLocationStockRecordMapper locationStockRecordMapper;
@Resource
private QrcodeRecordService qrcodeRecordService;
@Resource
private AutoCodeUtil autoCodeUtil;
@Resource
private AdminUserApi adminUserApi;
@Override
@Transactional(rollbackFor = Exception.class)
@ -111,6 +144,9 @@ public class BitWmsServiceImpl implements BitWmsService {
auditReqVO.setStatus(ErpAuditStatus.APPROVE.getStatus());
auditReqVO.setRemark(reqVO.getRemark() != null ? reqVO.getRemark() : "样品入库自动入库");
stockInService.auditStockIn(auditReqVO);
ErpStockInDO stockInDO = stockInService.getStockIn(id);
adjustLocationStock(product, location, reqVO.getCount(), "入库", SAMPLE_IN_TYPE, id,
stockInDO != null ? stockInDO.getNo() : null, reqVO.getRemark());
return id;
}
@ -118,7 +154,10 @@ public class BitWmsServiceImpl implements BitWmsService {
@Transactional(rollbackFor = Exception.class)
public Long outbound(BitWmsOutboundReqVO reqVO) {
ErpProductRespVO product = validateBitSample(reqVO.getProductId());
validateStockEnough(reqVO.getProductId(), reqVO.getWarehouseId(), reqVO.getAreaId(), reqVO.getCount());
WarehouseLocationDO location = resolveOutboundLocation(reqVO);
Long warehouseId = location.getWarehouseId();
Long areaId = location.getAreaId();
validateLocationStockEnough(reqVO.getProductId(), location.getId(), reqVO.getCount());
ErpStockOutSaveReqVO stockOut = new ErpStockOutSaveReqVO();
stockOut.setOutType(SAMPLE_OUT_TYPE);
@ -127,8 +166,8 @@ public class BitWmsServiceImpl implements BitWmsService {
ErpStockOutSaveReqVOItem item = new ErpStockOutSaveReqVOItem();
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.setRemark(reqVO.getRemark());
@ -139,6 +178,9 @@ public class BitWmsServiceImpl implements BitWmsService {
auditReqVO.setStatus(ErpAuditStatus.APPROVE.getStatus());
auditReqVO.setRemark(reqVO.getRemark() != null ? reqVO.getRemark() : "样品出库自动出库");
stockOutService.auditStockOut(auditReqVO);
ErpStockOutDO stockOutDO = stockOutService.getStockOut(id);
adjustLocationStock(product, location, reqVO.getCount().negate(), "出库", SAMPLE_OUT_TYPE, id,
stockOutDO != null ? stockOutDO.getNo() : null, buildOutboundRemark(reqVO.getOutReason(), reqVO.getRemark()));
return id;
}
@ -146,7 +188,20 @@ public class BitWmsServiceImpl implements BitWmsService {
@Transactional(rollbackFor = Exception.class)
public Long move(BitWmsMoveReqVO reqVO) {
ErpProductRespVO product = validateBitSample(reqVO.getProductId());
validateStockEnough(reqVO.getProductId(), reqVO.getFromWarehouseId(), reqVO.getFromAreaId(), reqVO.getCount());
WarehouseLocationDO fromLocation = resolveLocation(reqVO.getFromLocationId());
WarehouseLocationDO toLocation = resolveLocation(reqVO.getToLocationId());
validateLocationStockEnough(reqVO.getProductId(), fromLocation.getId(), reqVO.getCount());
if (fromLocation.getId().equals(toLocation.getId())) {
throw exception(STOCK_COUNT_NEGATIVE2, reqVO.getProductId(), fromLocation.getId());
}
if (isSameWarehouseArea(fromLocation, toLocation)) {
String bizNo = buildLocationMoveNo();
Long recordId = adjustLocationStock(product, fromLocation, reqVO.getCount().negate(), "出库",
SAMPLE_MOVE_TYPE + "出", null, bizNo, reqVO.getRemark());
adjustLocationStock(product, toLocation, reqVO.getCount(), "入库", SAMPLE_MOVE_TYPE + "入", null,
bizNo, reqVO.getRemark());
return recordId;
}
ErpStockMoveSaveReqVO stockMove = new ErpStockMoveSaveReqVO();
stockMove.setMoveTime(LocalDateTime.now());
@ -154,10 +209,10 @@ public class BitWmsServiceImpl implements BitWmsService {
ErpStockMoveSaveReqVO.Item item = new ErpStockMoveSaveReqVO.Item();
item.setProductId(reqVO.getProductId());
item.setFromWarehouseId(reqVO.getFromWarehouseId());
item.setFromAreaId(reqVO.getFromAreaId());
item.setToWarehouseId(reqVO.getToWarehouseId());
item.setToAreaId(reqVO.getToAreaId());
item.setFromWarehouseId(fromLocation.getWarehouseId());
item.setFromAreaId(fromLocation.getAreaId());
item.setToWarehouseId(toLocation.getWarehouseId());
item.setToAreaId(toLocation.getAreaId());
item.setCount(reqVO.getCount());
item.setProductPrice(product.getPurchasePrice() != null ? product.getPurchasePrice() : BigDecimal.ZERO);
item.setRemark(reqVO.getRemark());
@ -165,32 +220,106 @@ public class BitWmsServiceImpl implements BitWmsService {
Long id = stockMoveService.createStockMove(stockMove);
stockMoveService.updateStockMoveStatus(id, ErpAuditStatus.APPROVE.getStatus());
ErpStockMoveDO stockMoveDO = stockMoveService.getStockMove(id);
String bizNo = stockMoveDO != null ? stockMoveDO.getNo() : null;
adjustLocationStock(product, fromLocation, reqVO.getCount().negate(), "出库", SAMPLE_MOVE_TYPE + "出", id,
bizNo, reqVO.getRemark());
adjustLocationStock(product, toLocation, reqVO.getCount(), "入库", SAMPLE_MOVE_TYPE + "入", id,
bizNo, reqVO.getRemark());
return id;
}
@Override
public BitWmsScanRespVO scan(String code) {
ErpProductDO product = productMapper.selectOne(ErpProductDO::getBarCode, code);
String scanCode = code != null ? code.trim() : "";
BitWmsScanRespVO qrcodeBizRespVO = scanByQrcodeBizKey(scanCode);
if (qrcodeBizRespVO != null) {
return qrcodeBizRespVO;
}
ErpProductDO product = productMapper.selectOne(ErpProductDO::getBarCode, scanCode);
if (product != null && Boolean.TRUE.equals(product.getIsSample()) && BIT_BIZ_UNIT.equals(product.getBizUnit())) {
BitWmsScanRespVO respVO = new BitWmsScanRespVO();
respVO.setType(SAMPLE_TYPE);
respVO.setId(product.getId());
respVO.setCode(product.getBarCode());
respVO.setName(product.getName());
return respVO;
}
WarehouseLocationDO location = warehouseLocationMapper.selectByNo(code);
return buildSampleScanResp(product);
}
WarehouseLocationDO location = warehouseLocationMapper.selectByNo(scanCode);
if (location != null) {
BitWmsScanRespVO respVO = new BitWmsScanRespVO();
respVO.setType(LOCATION_TYPE);
respVO.setId(location.getId());
respVO.setCode(location.getCode());
respVO.setName(location.getName());
return respVO;
return buildLocationScanResp(location);
}
throw exception(PRODUCT_CODE_NOT_EXISTS);
}
private BitWmsScanRespVO scanByQrcodeBizKey(String code) {
Matcher matcher = QRCODE_BIZ_KEY_PATTERN.matcher(code);
if (!matcher.matches()) {
return null;
}
String bizType = matcher.group(1);
Long bizId = Long.valueOf(matcher.group(2));
if (QrcodeBizTypeEnum.PRODUCT.getCode().equalsIgnoreCase(bizType)) {
ErpProductDO product = productMapper.selectById(bizId);
if (product != null && Boolean.TRUE.equals(product.getIsSample()) && BIT_BIZ_UNIT.equals(product.getBizUnit())) {
return buildSampleScanResp(product);
}
throw exception(PRODUCT_CODE_NOT_EXISTS);
}
if (QrcodeBizTypeEnum.WAREHOUSE_LOCATION.getCode().equalsIgnoreCase(bizType)) {
WarehouseLocationDO location = warehouseLocationMapper.selectById(bizId);
if (location != null) {
return buildLocationScanResp(location);
}
throw exception(PRODUCT_CODE_NOT_EXISTS);
}
return null;
}
private BitWmsScanRespVO buildSampleScanResp(ErpProductDO product) {
BitWmsScanRespVO respVO = new BitWmsScanRespVO();
respVO.setType(SAMPLE_TYPE);
respVO.setId(product.getId());
respVO.setCode(product.getBarCode());
respVO.setName(product.getName());
return respVO;
}
private BitWmsScanRespVO buildLocationScanResp(WarehouseLocationDO location) {
BitWmsScanRespVO respVO = new BitWmsScanRespVO();
respVO.setType(LOCATION_TYPE);
respVO.setId(location.getId());
respVO.setCode(location.getCode());
respVO.setName(location.getName());
return respVO;
}
@Override
public PageResult<BitWmsLocationStockRespVO> getLocationStockPage(BitWmsLocationStockPageReqVO pageReqVO) {
PageResult<BitWmsLocationStockDO> pageResult = locationStockMapper.selectPage(pageReqVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return PageResult.empty(pageResult.getTotal());
}
LookupContext context = buildLookupContext(pageResult.getList(), null);
return BeanUtils.toBean(pageResult, BitWmsLocationStockRespVO.class,
stock -> fillLocationStockResp(stock, context));
}
@Override
public PageResult<BitWmsLocationStockRecordRespVO> getLocationStockRecordPage(BitWmsLocationStockRecordPageReqVO pageReqVO) {
PageResult<BitWmsLocationStockRecordDO> pageResult = locationStockRecordMapper.selectPage(pageReqVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return PageResult.empty(pageResult.getTotal());
}
LookupContext context = buildLookupContext(null, pageResult.getList());
return BeanUtils.toBean(pageResult, BitWmsLocationStockRecordRespVO.class,
record -> fillLocationStockRecordResp(record, context));
}
@Override
public BigDecimal getLocationStockCount(Long productId, Long locationId) {
validateBitSample(productId);
resolveLocation(locationId);
BitWmsLocationStockDO stock = locationStockMapper.selectByProductIdAndLocationId(productId, locationId);
return stock != null && stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO;
}
@Override
public BitWmsLabelRespVO getSampleLabel(Long productId) {
ErpProductRespVO product = validateBitSample(productId);
@ -251,12 +380,180 @@ public class BitWmsServiceImpl implements BitWmsService {
return location;
}
private void validateStockEnough(Long productId, Long warehouseId, Long areaId, BigDecimal count) {
ErpStockDO stock = stockService.getStock(productId, warehouseId, areaId);
private WarehouseLocationDO resolveOutboundLocation(BitWmsOutboundReqVO reqVO) {
return resolveLocation(reqVO.getLocationId());
}
private WarehouseLocationDO resolveLocation(Long locationId) {
WarehouseLocationDO location = warehouseLocationMapper.selectById(locationId);
if (location == null) {
throw exception(WAREHOUSE_LOCATION_NOT_EXISTS);
}
return location;
}
private void validateLocationStockEnough(Long productId, Long locationId, BigDecimal count) {
BitWmsLocationStockDO stock = locationStockMapper.selectByProductIdAndLocationId(productId, locationId);
BigDecimal currentCount = stock != null && stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO;
if (currentCount.compareTo(count) < 0) {
throw exception(STOCK_COUNT_NEGATIVE2, productId, warehouseId);
throw exception(STOCK_COUNT_NEGATIVE2, productId, locationId);
}
}
private Long adjustLocationStock(ErpProductRespVO product, WarehouseLocationDO location, BigDecimal count,
String direction, String bizType, Long bizId, String bizNo, String remark) {
BitWmsLocationStockDO stock = locationStockMapper.selectByProductIdAndLocationId(product.getId(), location.getId());
if (stock == null) {
if (count.compareTo(BigDecimal.ZERO) < 0) {
throw exception(STOCK_COUNT_NEGATIVE2, product.getId(), location.getId());
}
stock = new BitWmsLocationStockDO()
.setProductId(product.getId())
.setWarehouseId(location.getWarehouseId())
.setAreaId(location.getAreaId())
.setLocationId(location.getId())
.setCount(count)
.setUnitId(product.getUnitId());
locationStockMapper.insert(stock);
} else {
int updated = locationStockMapper.updateCountIncrement(stock.getId(), count, false);
if (updated == 0 && count.compareTo(BigDecimal.ZERO) < 0) {
throw exception(STOCK_COUNT_NEGATIVE2, product.getId(), location.getId());
}
stock = locationStockMapper.selectById(stock.getId());
}
BitWmsLocationStockRecordDO record = new BitWmsLocationStockRecordDO()
.setProductId(product.getId())
.setWarehouseId(location.getWarehouseId())
.setAreaId(location.getAreaId())
.setLocationId(location.getId())
.setCount(count.abs())
.setTotalCount(stock.getCount())
.setUnitId(product.getUnitId())
.setBizDirection(direction)
.setBizType(bizType)
.setBizId(bizId)
.setBizNo(bizNo)
.setRemark(remark)
.setRecordTime(LocalDateTime.now());
locationStockRecordMapper.insert(record);
return record.getId();
}
private boolean isSameWarehouseArea(WarehouseLocationDO fromLocation, WarehouseLocationDO toLocation) {
return fromLocation.getWarehouseId().equals(toLocation.getWarehouseId())
&& java.util.Objects.equals(fromLocation.getAreaId(), toLocation.getAreaId());
}
private String buildLocationMoveNo() {
return "KWYK" + System.currentTimeMillis();
}
private LookupContext buildLookupContext(List<BitWmsLocationStockDO> stocks,
List<BitWmsLocationStockRecordDO> records) {
Set<Long> productIds = new HashSet<>();
Set<Long> warehouseIds = new HashSet<>();
Set<Long> areaIds = new HashSet<>();
Set<Long> locationIds = new HashSet<>();
Set<Long> creatorIds = new HashSet<>();
if (stocks != null) {
for (BitWmsLocationStockDO stock : stocks) {
collectCommonIds(productIds, warehouseIds, areaIds, locationIds,
stock.getProductId(), stock.getWarehouseId(), stock.getAreaId(), stock.getLocationId());
}
}
if (records != null) {
for (BitWmsLocationStockRecordDO record : records) {
collectCommonIds(productIds, warehouseIds, areaIds, locationIds,
record.getProductId(), record.getWarehouseId(), record.getAreaId(), record.getLocationId());
if (record.getCreator() != null) {
creatorIds.add(Long.parseLong(record.getCreator()));
}
}
}
LookupContext context = new LookupContext();
context.productMap = productIds.isEmpty() ? Collections.emptyMap() : productService.getProductVOMap(productIds);
context.warehouseMap = warehouseIds.isEmpty() ? Collections.emptyMap() : warehouseService.getWarehouseMap(warehouseIds);
context.areaMap = areaIds.isEmpty() ? Collections.emptyMap() : warehouseAreaService.getWarehouseAreaMap(areaIds);
context.locationMap = locationIds.isEmpty() ? Collections.emptyMap()
: warehouseLocationMapper.selectBatchIds(locationIds).stream()
.collect(Collectors.toMap(WarehouseLocationDO::getId, item -> item, (a, b) -> a));
context.userMap = creatorIds.isEmpty() ? Collections.emptyMap() : adminUserApi.getUserMap(creatorIds);
return context;
}
private void collectCommonIds(Set<Long> productIds, Set<Long> warehouseIds, Set<Long> areaIds, Set<Long> locationIds,
Long productId, Long warehouseId, Long areaId, Long locationId) {
if (productId != null) {
productIds.add(productId);
}
if (warehouseId != null) {
warehouseIds.add(warehouseId);
}
if (areaId != null) {
areaIds.add(areaId);
}
if (locationId != null) {
locationIds.add(locationId);
}
}
private void fillLocationStockResp(BitWmsLocationStockRespVO respVO, LookupContext context) {
ErpProductRespVO product = context.productMap.get(respVO.getProductId());
if (product != null) {
respVO.setProductName(product.getName());
respVO.setBarCode(product.getBarCode());
respVO.setSampleCategory(product.getSampleCategory());
respVO.setCustomerName(product.getCustomerName());
respVO.setUnitName(product.getUnitName());
}
fillLocationInfo(respVO.getWarehouseId(), respVO.getAreaId(), respVO.getLocationId(), context,
respVO::setWarehouseName, respVO::setAreaName, respVO::setLocationCode, respVO::setLocationName);
}
private void fillLocationStockRecordResp(BitWmsLocationStockRecordRespVO respVO, LookupContext context) {
ErpProductRespVO product = context.productMap.get(respVO.getProductId());
if (product != null) {
respVO.setProductName(product.getName());
respVO.setBarCode(product.getBarCode());
respVO.setUnitName(product.getUnitName());
}
fillLocationInfo(respVO.getWarehouseId(), respVO.getAreaId(), respVO.getLocationId(), context,
respVO::setWarehouseName, respVO::setAreaName, respVO::setLocationCode, respVO::setLocationName);
if (respVO.getCreator() != null) {
AdminUserRespDTO user = context.userMap.get(Long.parseLong(respVO.getCreator()));
if (user != null) {
respVO.setCreatorName(user.getNickname());
}
}
}
private void fillLocationInfo(Long warehouseId, Long areaId, Long locationId, LookupContext context,
java.util.function.Consumer<String> warehouseSetter,
java.util.function.Consumer<String> areaSetter,
java.util.function.Consumer<String> locationCodeSetter,
java.util.function.Consumer<String> locationNameSetter) {
ErpWarehouseDO warehouse = context.warehouseMap.get(warehouseId);
if (warehouse != null) {
warehouseSetter.accept(warehouse.getName());
}
WarehouseAreaDO area = context.areaMap.get(areaId);
if (area != null) {
areaSetter.accept(area.getAreaName());
}
WarehouseLocationDO location = context.locationMap.get(locationId);
if (location != null) {
locationCodeSetter.accept(location.getCode());
locationNameSetter.accept(location.getName());
}
}
private static class LookupContext {
private Map<Long, ErpProductRespVO> productMap;
private Map<Long, ErpWarehouseDO> warehouseMap;
private Map<Long, WarehouseAreaDO> areaMap;
private Map<Long, WarehouseLocationDO> locationMap;
private Map<Long, AdminUserRespDTO> userMap;
}
private String buildOutboundRemark(String outReason, String remark) {

@ -9,12 +9,14 @@ import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsInboundReqVO
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.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.dal.dataobject.product.ErpProductDO;
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;
@ -25,6 +27,7 @@ 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 com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
@ -34,8 +37,10 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_CODE_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;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@ -70,6 +75,66 @@ class BitWmsServiceImplTest {
@Mock
private AutoCodeUtil autoCodeUtil;
@Test
void scan_whenProductQrcodeBizKey_returnsSample() {
when(productMapper.selectById(332L)).thenReturn(buildBitSampleProductDO(332L));
BitWmsScanRespVO respVO = bitWmsService.scan(" PRODUCTMATERIAL-332 ");
assertEquals("SAMPLE", respVO.getType());
assertEquals(332L, respVO.getId());
assertEquals("SP001", respVO.getCode());
assertEquals("BIT 样品", respVO.getName());
}
@Test
void scan_whenLocationQrcodeBizKey_returnsLocation() {
when(warehouseLocationMapper.selectById(5L)).thenReturn(new WarehouseLocationDO()
.setId(5L).setCode("KW001").setName("必硕三楼 A01"));
BitWmsScanRespVO respVO = bitWmsService.scan("warehouse_location_5");
assertEquals("LOCATION", respVO.getType());
assertEquals(5L, respVO.getId());
assertEquals("KW001", respVO.getCode());
assertEquals("必硕三楼 A01", respVO.getName());
}
@Test
void scan_whenProductQrcodeBizKeyIsNotBitSample_throwsException() {
ErpProductDO product = buildBitSampleProductDO(332L);
product.setIsSample(false);
when(productMapper.selectById(332L)).thenReturn(product);
AssertUtils.assertServiceException(() -> bitWmsService.scan("PRODUCTMATERIAL-332"), PRODUCT_CODE_NOT_EXISTS);
}
@Test
void scan_whenPlainSampleCode_returnsSample() {
when(productMapper.selectOne(org.mockito.ArgumentMatchers.<SFunction<ErpProductDO, ?>>any(), eq("SP001")))
.thenReturn(buildBitSampleProductDO(332L));
BitWmsScanRespVO respVO = bitWmsService.scan("SP001");
assertEquals("SAMPLE", respVO.getType());
assertEquals(332L, respVO.getId());
assertEquals("SP001", respVO.getCode());
assertEquals("BIT 样品", respVO.getName());
}
@Test
void scan_whenPlainLocationCode_returnsLocation() {
when(warehouseLocationMapper.selectByNo("KW001")).thenReturn(new WarehouseLocationDO()
.setId(5L).setCode("KW001").setName("必硕三楼 A01"));
BitWmsScanRespVO respVO = bitWmsService.scan("KW001");
assertEquals("LOCATION", respVO.getType());
assertEquals(5L, respVO.getId());
assertEquals("KW001", respVO.getCode());
assertEquals("必硕三楼 A01", respVO.getName());
}
@Test
void inbound_createsSampleStockInWithBitType() {
BitWmsInboundReqVO reqVO = new BitWmsInboundReqVO();
@ -170,12 +235,15 @@ class BitWmsServiceImplTest {
void outbound_rejectsCountGreaterThanLocationStock() {
BitWmsOutboundReqVO reqVO = new BitWmsOutboundReqVO();
reqVO.setProductId(10L);
reqVO.setWarehouseId(20L);
reqVO.setAreaId(30L);
reqVO.setWarehouseId(999L);
reqVO.setAreaId(998L);
reqVO.setLocationId(88L);
reqVO.setCount(new BigDecimal("999"));
reqVO.setOutReason("TEST");
when(productService.getProduct(10L)).thenReturn(buildBitSampleProduct());
when(warehouseLocationMapper.selectById(88L)).thenReturn(new WarehouseLocationDO()
.setId(88L).setWarehouseId(20L).setAreaId(30L));
when(stockService.getStock(10L, 20L, 30L)).thenReturn(new ErpStockDO().setCount(BigDecimal.ONE));
AssertUtils.assertServiceException(() -> bitWmsService.outbound(reqVO), STOCK_COUNT_NEGATIVE2, 10L, 20L);
@ -185,13 +253,16 @@ class BitWmsServiceImplTest {
void outbound_createsSampleStockOutAndAutoApproves() {
BitWmsOutboundReqVO reqVO = new BitWmsOutboundReqVO();
reqVO.setProductId(10L);
reqVO.setWarehouseId(20L);
reqVO.setAreaId(30L);
reqVO.setWarehouseId(999L);
reqVO.setAreaId(998L);
reqVO.setLocationId(88L);
reqVO.setCount(new BigDecimal("1"));
reqVO.setOutReason("TEST");
reqVO.setRemark("out remark");
when(productService.getProduct(10L)).thenReturn(buildBitSampleProduct());
when(warehouseLocationMapper.selectById(88L)).thenReturn(new WarehouseLocationDO()
.setId(88L).setWarehouseId(20L).setAreaId(30L));
when(stockService.getStock(10L, 20L, 30L)).thenReturn(new ErpStockDO().setCount(new BigDecimal("2")));
when(stockOutService.createStockOut(org.mockito.ArgumentMatchers.any(ErpStockOutSaveReqVO.class))).thenReturn(200L);
@ -216,6 +287,22 @@ class BitWmsServiceImplTest {
assertEquals("out remark", auditCaptor.getValue().getRemark());
}
@Test
void outbound_whenLocationNotExists_throwsException() {
BitWmsOutboundReqVO reqVO = new BitWmsOutboundReqVO();
reqVO.setProductId(10L);
reqVO.setWarehouseId(20L);
reqVO.setAreaId(30L);
reqVO.setLocationId(88L);
reqVO.setCount(new BigDecimal("1"));
reqVO.setOutReason("TEST");
when(productService.getProduct(10L)).thenReturn(buildBitSampleProduct());
when(warehouseLocationMapper.selectById(88L)).thenReturn(null);
AssertUtils.assertServiceException(() -> bitWmsService.outbound(reqVO), WAREHOUSE_LOCATION_NOT_EXISTS);
}
@Test
void move_keepsTotalStockAndChangesLocation() {
BitWmsMoveReqVO reqVO = new BitWmsMoveReqVO();
@ -307,4 +394,13 @@ class BitWmsServiceImplTest {
product.setUnitName("个");
return product;
}
private ErpProductDO buildBitSampleProductDO(Long id) {
return new ErpProductDO()
.setId(id)
.setName("BIT 样品")
.setBarCode("SP001")
.setIsSample(true)
.setBizUnit("BIT");
}
}

Loading…
Cancel
Save