diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
index 5cfec682c..3f98d4314 100644
--- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
+++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
@@ -25,7 +25,7 @@ public interface ErrorCodeConstants {
ErrorCode STOCK_IN_DELETE_FAIL_APPROVE = new ErrorCode(1_030_401_001, "其它入库单({})已审核,无法删除");
ErrorCode STOCK_IN_PROCESS_FAIL = new ErrorCode(1_030_401_002, "反审核失败,只有已审核的入库单才能反审核");
ErrorCode STOCK_IN_APPROVE_FAIL = new ErrorCode(1_030_401_003, "审核失败,只有未审核的入库单才能审核");
-
+ ErrorCode STOCK_IN_NO_EXISTS = new ErrorCode(1_030_401_004, "生成入库单失败,请重新提交");
// ========== ERP 产品 1-030-500-000 ==========
ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在");
diff --git a/yudao-module-erp/yudao-module-erp-biz/pom.xml b/yudao-module-erp/yudao-module-erp-biz/pom.xml
index 83b3900cf..1d0b44162 100644
--- a/yudao-module-erp/yudao-module-erp-biz/pom.xml
+++ b/yudao-module-erp/yudao-module-erp-biz/pom.xml
@@ -51,6 +51,11 @@
yudao-spring-boot-starter-mybatis
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-redis
+
+
cn.iocoder.boot
diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java
index e3a87da8a..0187872c8 100644
--- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java
+++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java
@@ -17,10 +17,6 @@ public class ErpStockInSaveReqVO {
@Schema(description = "入库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756")
private Long id;
- @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123")
- @NotEmpty(message = "入库单号不能为空")
- private String no;
-
@Schema(description = "供应商编号", example = "3113")
private Long supplierId;
diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java
index eadf02c75..9e7ea9bca 100644
--- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java
+++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java
@@ -40,4 +40,8 @@ public interface ErpStockInMapper extends BaseMapperX {
.eq(ErpStockInDO::getId, id).eq(ErpStockInDO::getStatus, status));
}
+ default ErpStockInDO selectByNo(String no) {
+ return selectOne(ErpStockInDO::getNo, no);
+ }
+
}
\ No newline at end of file
diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java
new file mode 100644
index 000000000..f0ba46807
--- /dev/null
+++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.erp.dal.redis;
+
+/**
+ * ERP Redis Key 枚举类
+ *
+ * @author 芋道源码
+ */
+public interface RedisKeyConstants {
+
+ /**
+ * 序号的缓存
+ *
+ * KEY 格式:trade_no:{prefix}
+ * VALUE 数据格式:编号自增
+ */
+ String NO = "seq_no:";
+
+}
diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
new file mode 100644
index 000000000..e211864cc
--- /dev/null
+++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.erp.dal.redis.no;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.iocoder.yudao.module.erp.dal.redis.RedisKeyConstants;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Repository;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+
+/**
+ * 订单序号的 Redis DAO
+ *
+ * @author HUIHUI
+ */
+@Repository
+public class ErpNoRedisDAO {
+
+ /**
+ * 其它入库 STOCK_IN
+ */
+ public static final String STOCK_IN_NO_PREFIX = "QTRK";
+
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+
+ /**
+ * 生成序号,使用当前日期,格式为 {PREFIX} + yyyyMMdd + 6 位自增
+ * 例如说:QTRK 202109 000001 (没有中间空格)
+ *
+ * @param prefix 前缀
+ * @return 序号
+ */
+ public String generate(String prefix) {
+ // 递增序号
+ String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
+ String key = RedisKeyConstants.NO + noPrefix;
+ Long no = stringRedisTemplate.opsForValue().increment(key);
+ // 设置过期时间
+ stringRedisTemplate.expire(key, Duration.ofMinutes(1L));
+ return noPrefix + String.format("%06d", no);
+ }
+
+}
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 305676445..8f4835013 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
@@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper;
+import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO;
import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService;
@@ -44,6 +45,9 @@ public class ErpStockInServiceImpl implements ErpStockInService {
@Resource
private ErpStockInItemMapper stockInItemMapper;
+ @Resource
+ private ErpNoRedisDAO noRedisDAO;
+
@Resource
private ErpProductService productService;
@Resource
@@ -58,10 +62,15 @@ public class ErpStockInServiceImpl implements ErpStockInService {
List stockInItems = validateStockInItems(createReqVO.getItems());
// 1.2 校验供应商
supplierService.validateSupplier(createReqVO.getSupplierId());
+ // 1.3
+ String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_IN_NO_PREFIX);
+ if (stockInMapper.selectByNo(no) != null) {
+ throw exception(STOCK_IN_NO_EXISTS);
+ }
// 2.1 插入入库单
ErpStockInDO stockIn = BeanUtils.toBean(createReqVO, ErpStockInDO.class, in -> in
- .setStatus(ErpAuditStatus.PROCESS.getStatus())
+ .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())
.setTotalCount(getSumValue(stockInItems, ErpStockInItemDO::getCount, BigDecimal::add))
.setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)));
stockInMapper.insert(stockIn);