From b852254d90e7d1955db31db154193ec8ee84d8b3 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 09 九月 2026 10:57:59 +0800
Subject: [PATCH] feat(hrm): 新增员工用工性质、班组归属字段及考勤异常处理优化

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java |  136 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 131 insertions(+), 5 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java
index e07b1c4..2bed5cd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java
@@ -2,33 +2,53 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnDetailRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGenerateReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGroupRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnInStockPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnInStockReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnOutStockReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnPageReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.sn.MesWmSnDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transaction.MesWmTransactionDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.sn.MesWmSnMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.transaction.MesWmTransactionMapper;
+import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
 import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
 import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmSnStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
 import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
-import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
 import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
 
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
 /**
  * MES SN 鐮� Service 瀹炵幇绫�
  *
- * @author 鑺嬮亾婧愮爜
+ * @author 瓒呯骇绠$悊鍛�
  */
 @Service
 @Validated
@@ -37,21 +57,31 @@
 
     @Resource
     private MesWmSnMapper snMapper;
+    @Resource
+    private MesWmTransactionMapper transactionMapper;
 
     @Resource
     private MesMdAutoCodeRecordService autoCodeRecordService;
     @Resource
-    private MesMdItemService itemService;
+    private MesMdmItemService mdmItemService;
     @Resource
     private MesProWorkOrderService workOrderService;
     @Resource
     private MesWmBarcodeService barcodeService;
+    @Resource
+    private MesWmTransactionService transactionService;
+    @Resource
+    private MesWmWarehouseService warehouseService;
+    @Resource
+    private MesWmWarehouseLocationService locationService;
+    @Resource
+    private MesWmWarehouseAreaService areaService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void generateSnCodes(MesWmSnGenerateReqVO reqVO) {
         // 鏍¢獙鐗╂枡鏄惁瀛樺湪
-        itemService.validateItemExists(reqVO.getItemId());
+        mdmItemService.validateItemExists(reqVO.getItemId());
         // 鏍¢獙宸ュ崟鏄惁瀛樺湪
         if (reqVO.getWorkOrderId() != null) {
             workOrderService.validateWorkOrderExists(reqVO.getWorkOrderId());
@@ -99,4 +129,100 @@
         snMapper.deleteByUuid(uuid);
     }
 
-}
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void registerSnInStock(MesWmSnInStockReqVO reqVO) {
+        // 1. 鏍¢獙 SN 瀛樺湪涓旂墿鏂欏尮閰�
+        MesWmSnDO sn = validateSnExists(reqVO.getCode());
+        validateSnItemMatch(sn, reqVO.getItemId());
+        // 2. 鏍¢獙鐗╂枡鍚敤搴忓垪鍙风鐞�
+        MesMdmItemDO item = mdmItemService.validateItemExists(reqVO.getItemId());
+        if (!Boolean.TRUE.equals(item.getIsSerialManaged())) {
+            throw exception(WM_SN_ITEM_NOT_SERIAL);
+        }
+        // 3. 鐘舵�佹牎楠岋細宸插湪搴撳垯鎷掔粷閲嶅鐧昏
+        if (ObjUtil.equal(sn.getStatus(), MesWmSnStatusEnum.IN_STOCK.getStatus())) {
+            throw exception(WM_SN_ALREADY_IN_STOCK);
+        }
+        // 4. 鏍¢獙搴撳瓨浣嶇疆瀛樺湪锛堝喕缁撲笌娣锋斁瑙勫垯鐢变簨鍔″唴閮ㄥ厹搴曪級
+        warehouseService.validateWarehouseExists(reqVO.getWarehouseId());
+        locationService.validateWarehouseLocationExists(reqVO.getLocationId());
+        areaService.validateWarehouseAreaExists(reqVO.getAreaId());
+        // 5. 鍒涘缓鍗曚欢鍏ュ簱浜嬪姟锛�+1锛�
+        transactionService.createTransaction(new MesWmTransactionSaveReqDTO()
+                .setType(MesWmTransactionTypeEnum.IN.getType())
+                .setBizType(MesBizTypeConstants.WM_SN)
+                .setBizId(sn.getId()).setBizCode(sn.getCode()).setBizLineId(sn.getId())
+                .setItemId(sn.getItemId()).setQuantity(BigDecimal.ONE)
+                .setBatchId(sn.getBatchId()).setBatchCode(sn.getBatchCode())
+                .setSnCode(sn.getCode())
+                .setWarehouseId(reqVO.getWarehouseId()).setLocationId(reqVO.getLocationId()).setAreaId(reqVO.getAreaId()));
+        // 6. 鏇存柊 SN锛氬湪搴� + 璁板綍搴撲綅
+        snMapper.updateById(new MesWmSnDO().setId(sn.getId())
+                .setStatus(MesWmSnStatusEnum.IN_STOCK.getStatus())
+                .setWarehouseId(reqVO.getWarehouseId()).setLocationId(reqVO.getLocationId()).setAreaId(reqVO.getAreaId())
+                .setRemark(reqVO.getRemark()));
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void outboundSn(MesWmSnOutStockReqVO reqVO) {
+        // 1. 鏍¢獙 SN 瀛樺湪涓旂墿鏂欏尮閰�
+        MesWmSnDO sn = validateSnExists(reqVO.getCode());
+        validateSnItemMatch(sn, reqVO.getItemId());
+        // 2. 鐘舵�佹牎楠岋細蹇呴』鍦ㄥ簱涓旇褰曡繃搴撲綅
+        if (!ObjUtil.equal(sn.getStatus(), MesWmSnStatusEnum.IN_STOCK.getStatus())
+                || sn.getWarehouseId() == null || sn.getLocationId() == null || sn.getAreaId() == null) {
+            throw exception(WM_SN_NOT_IN_STOCK);
+        }
+        // 3. 鍒涘缓鍗曚欢鍑哄簱浜嬪姟锛�-1锛夛紝鎸� SN 鍦ㄥ簱浣嶇疆绮剧‘瀹氫綅搴撳瓨璁板綍
+        transactionService.createTransaction(new MesWmTransactionSaveReqDTO()
+                .setType(MesWmTransactionTypeEnum.OUT.getType())
+                .setBizType(MesBizTypeConstants.WM_SN)
+                .setBizId(sn.getId()).setBizCode(sn.getCode()).setBizLineId(sn.getId())
+                .setItemId(sn.getItemId()).setQuantity(BigDecimal.ONE.negate())
+                .setBatchId(sn.getBatchId()).setBatchCode(sn.getBatchCode())
+                .setSnCode(sn.getCode())
+                .setWarehouseId(sn.getWarehouseId()).setLocationId(sn.getLocationId()).setAreaId(sn.getAreaId()));
+        // 4. 鏇存柊 SN锛氬凡鍑哄簱 + 娓呯┖鍦ㄥ簱浣嶇疆
+        snMapper.markOutStockAndClearLocation(sn.getId());
+        snMapper.updateById(new MesWmSnDO().setId(sn.getId()).setRemark(reqVO.getRemark()));
+    }
+
+    @Override
+    public MesWmSnDetailRespVO getSnDetail(String snCode) {
+        MesWmSnDO sn = validateSnExists(snCode);
+        MesWmSnDetailRespVO resp = BeanUtils.toBean(sn, MesWmSnDetailRespVO.class);
+        MesWmTransactionDO transaction = transactionMapper.selectLatestBySnCode(snCode);
+        if (transaction != null) {
+            MesWmTransactionTypeEnum typeEnum = MesWmTransactionTypeEnum.valueOf(transaction.getType());
+            resp.setLastTransactionType(transaction.getType());
+            resp.setLastTransactionTypeName(typeEnum != null ? typeEnum.getName() : null);
+            resp.setLastTransactionQuantity(transaction.getQuantity());
+            resp.setLastTransactionBizType(transaction.getBizType());
+            resp.setLastTransactionBizCode(transaction.getBizCode());
+            resp.setLastTransactionTime(transaction.getTransactionTime());
+        }
+        return resp;
+    }
+
+    @Override
+    public PageResult<MesWmSnDO> getSnInStockPage(MesWmSnInStockPageReqVO reqVO) {
+        return snMapper.selectStatusPage(reqVO);
+    }
+
+    private MesWmSnDO validateSnExists(String code) {
+        MesWmSnDO sn = snMapper.selectByCode(code);
+        if (sn == null) {
+            throw exception(WM_SN_NOT_EXISTS);
+        }
+        return sn;
+    }
+
+    private void validateSnItemMatch(MesWmSnDO sn, Long itemId) {
+        if (ObjUtil.notEqual(sn.getItemId(), itemId)) {
+            throw exception(WM_SN_ITEM_MISMATCH);
+        }
+    }
+
+}
\ No newline at end of file

--
Gitblit v1.9.3