From 111270df037596a04df97f787ca8b9199dd99866 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 20 七月 2026 17:28:31 +0800
Subject: [PATCH] feat(crm): 增加商机客户团队权限校验功能
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java | 37 +++++++++
yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApi.java | 20 +++++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsService.java | 11 ++
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java | 10 ++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApiImpl.java | 11 ++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java | 32 +++++--
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java | 38 ++++++++-
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemService.java | 7 +
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java | 58 +++++++++++++-
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java | 9 ++
10 files changed, 213 insertions(+), 20 deletions(-)
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java
index d490258..0ae9370 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java
@@ -5,7 +5,9 @@
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
+import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
+import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
@@ -43,6 +45,9 @@
@Resource
private AdminUserApi adminUserApi;
+ @Resource
+ private CrmBusinessMapper businessMapper;
+
@Before("@annotation(crmPermission)")
public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) {
// 1.1 鑾峰彇鐩稿叧灞炴�у��
@@ -62,10 +67,10 @@
// 2. 閫愪釜鏍¢獙鏉冮檺
List<CrmPermissionDO> permissionList = crmPermissionService.getPermissionListByBiz(bizType, bizIds);
Map<Long, List<CrmPermissionDO>> multiMap = convertMultiMap(permissionList, CrmPermissionDO::getBizId);
- bizIds.forEach(bizId -> validatePermission(bizType, multiMap.get(bizId), permissionLevel));
+ bizIds.forEach(bizId -> validatePermission(bizType, bizId, multiMap.get(bizId), permissionLevel));
}
- private void validatePermission(Integer bizType, List<CrmPermissionDO> bizPermissions, Integer permissionLevel) {
+ private void validatePermission(Integer bizType, Long bizId, List<CrmPermissionDO> bizPermissions, Integer permissionLevel) {
// 1. 濡傛灉鏄秴绾х鐞嗗憳鍒欑洿鎺ラ�氳繃
if (CrmPermissionUtils.isCrmAdmin()) {
return;
@@ -85,7 +90,7 @@
}
}
- // 2. 鍙�冭檻鑷殑韬潈闄�
+ // 2. 鍙�冭檻鑷韩鐨勬潈闄�
Long userId = getUserId();
CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, permission -> ObjUtil.equal(permission.getUserId(), userId));
if (userPermission != null) {
@@ -94,7 +99,14 @@
}
}
- // 3. 鑰冭檻涓嬬骇鐨勬潈闄�
+ // 3. 鍟嗘満鐗规畩澶勭悊锛氭鏌ュ鎴峰洟闃熸潈闄�
+ if (CrmBizTypeEnum.CRM_BUSINESS.getType().equals(bizType)) {
+ if (validateBusinessCustomerPermission(bizId, userId, permissionLevel)) {
+ return;
+ }
+ }
+
+ // 4. 鑰冭檻涓嬬骇鐨勬潈闄�
List<AdminUserRespDTO> subordinateUserIds = adminUserApi.getUserListBySubordinate(userId);
for (Long subordinateUserId : convertSet(subordinateUserIds, AdminUserRespDTO::getId)) {
CrmPermissionDO subordinatePermission = CollUtil.findOne(bizPermissions,
@@ -102,15 +114,51 @@
if (subordinatePermission != null && isUserPermissionValid(subordinatePermission, permissionLevel)) {
return;
}
+ // 鍟嗘満鐗规畩澶勭悊锛氭鏌ュ鎴峰洟闃熸潈闄愶紙涓嬪睘鐨勶級
+ if (CrmBizTypeEnum.CRM_BUSINESS.getType().equals(bizType)) {
+ if (validateBusinessCustomerPermission(bizId, subordinateUserId, permissionLevel)) {
+ return;
+ }
+ }
}
- // 4. 娌℃湁鏉冮檺锛屾姏鍑哄紓甯�
+ // 5. 娌℃湁鏉冮檺锛屾姏鍑哄紓甯�
log.info("[doBefore][userId({}) 瑕佹眰鏉冮檺({}) 瀹為檯鏉冮檺({}) 鏁版嵁鏍¢獙閿欒]", // 鎵撲釜 info 鏃ュ織锛屾柟渚垮悗缁帓鏌ラ棶棰樸�佸璁�
userId, permissionLevel, toJsonString(userPermission));
throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType));
}
/**
+ * 鍟嗘満鐗规畩鏉冮檺鏍¢獙锛氭鏌ョ敤鎴锋槸鍚︽湁璇ュ晢鏈烘墍灞炲鎴风殑鍥㈤槦鏉冮檺
+ *
+ * @param businessId 鍟嗘満缂栧彿
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param permissionLevel 闇�瑕佺殑鏉冮檺绾у埆
+ * @return 鏄惁鏈夋潈闄�
+ */
+ private boolean validateBusinessCustomerPermission(Long businessId, Long userId, Integer permissionLevel) {
+ // 鑾峰彇鍟嗘満鐨勫鎴稩D
+ CrmBusinessDO business = businessMapper.selectById(businessId);
+ if (business == null || business.getCustomerId() == null) {
+ return false;
+ }
+ // 妫�鏌ュ鎴峰洟闃熸潈闄�
+ List<CrmPermissionDO> customerPermissions = crmPermissionService.getPermissionListByBiz(
+ CrmBizTypeEnum.CRM_CUSTOMER.getType(), Collections.singleton(business.getCustomerId()));
+ if (CollUtil.isEmpty(customerPermissions)) {
+ // 瀹㈡埛鍏捣鏁版嵁锛孯EAD 鏉冮檺鏀捐
+ return CrmPermissionLevelEnum.isRead(permissionLevel);
+ }
+ // 妫�鏌ョ敤鎴锋槸鍚︽湁瀹㈡埛鍥㈤槦鐨勬潈闄�
+ CrmPermissionDO userCustomerPermission = CollUtil.findOne(customerPermissions,
+ permission -> ObjUtil.equal(permission.getUserId(), userId));
+ if (userCustomerPermission != null && isUserPermissionValid(userCustomerPermission, permissionLevel)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* 鏍¢獙鐢ㄦ埛鏉冮檺鏄惁鏈夋晥
*
* @param userPermission 鐢ㄦ埛鎷ユ湁鐨勬潈闄�
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java
index 0563af0..c97266b 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java
@@ -58,11 +58,16 @@
if (CrmPermissionUtils.isCrmAdmin()) { // 鐗规畩閫昏緫锛氬鏋滄槸瓒呯锛岀洿鎺ユ煡璇㈡墍鏈夛紝涓嶈繃婊ゆ暟鎹潈闄�
return;
}
- query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType)
- .eq(CrmPermissionDO::getBizId, bizId)
- .in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel())
- .eq(CrmPermissionDO::getUserId,userId));
- query.ne(ownerUserIdField, userId);
+ // 鍟嗘満鐗规畩澶勭悊锛氬悓鏃跺叧鑱斿晢鏈哄洟闃熷拰瀹㈡埛鍥㈤槦鐨勬潈闄�
+ if (CrmBizTypeEnum.CRM_BUSINESS.getType().equals(bizType)) {
+ appendBusinessPermissionCondition(query, bizId, userId, ownerUserIdField);
+ } else {
+ query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType)
+ .eq(CrmPermissionDO::getBizId, bizId)
+ .in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel())
+ .eq(CrmPermissionDO::getUserId, userId));
+ query.ne(ownerUserIdField, userId);
+ }
}
// 鍦烘櫙涓夛細涓嬪睘璐熻矗鐨勬暟鎹紙涓嬪睘鏄礋璐d汉锛�
if (CrmSceneTypeEnum.isSubordinate(sceneType)) {
@@ -76,4 +81,27 @@
}
}
+ /**
+ * 鍟嗘満鐗规畩鏉冮檺鏉′欢锛氬悓鏃跺叧鑱斿晢鏈哄洟闃熷拰瀹㈡埛鍥㈤槦鐨勬潈闄�
+ * 鍟嗘満缁ф壙瀹㈡埛鍥㈤槦鐨勬潈闄愶紝鍗冲鎴峰洟闃熸垚鍛樹篃鑳界湅鍒拌瀹㈡埛涓嬬殑鍟嗘満
+ */
+ private static <T extends MPJLambdaWrapper<?>, S> void appendBusinessPermissionCondition(T query, SFunction<S, ?> bizId,
+ Long userId, String ownerUserIdField) {
+ // 浣跨敤瀛愭煡璇㈡柟寮忥細鍟嗘満鍥㈤槦鎴愬憳 OR 瀹㈡埛鍥㈤槦鎴愬憳
+ // 瀛愭煡璇�1锛氬晢鏈哄洟闃熸垚鍛樻潈闄�
+ String subQuery1 = "(SELECT p1.biz_id FROM crm_permission p1 " +
+ "WHERE p1.biz_type = " + CrmBizTypeEnum.CRM_BUSINESS.getType() + " " +
+ "AND p1.level IN (" + CrmPermissionLevelEnum.READ.getLevel() + "," + CrmPermissionLevelEnum.WRITE.getLevel() + ") " +
+ "AND p1.user_id = " + userId + ")";
+ // 瀛愭煡璇�2锛氬鎴峰洟闃熸垚鍛樻潈闄愶紙閫氳繃鍟嗘満鐨� customer_id 鍏宠仈锛�
+ String subQuery2 = "(SELECT b.id FROM crm_business b " +
+ "INNER JOIN crm_permission p2 ON p2.biz_type = " + CrmBizTypeEnum.CRM_CUSTOMER.getType() + " " +
+ "AND p2.biz_id = b.customer_id " +
+ "AND p2.level IN (" + CrmPermissionLevelEnum.READ.getLevel() + "," + CrmPermissionLevelEnum.WRITE.getLevel() + ") " +
+ "AND p2.user_id = " + userId + ")";
+ // 浣跨敤 OR 杩炴帴涓や釜瀛愭煡璇紝骞舵帓闄よ嚜宸辨槸璐熻矗浜虹殑鎯呭喌
+ query.apply("t.id IN (" + subQuery1 + " UNION " + subQuery2 + ")")
+ .ne(ownerUserIdField, userId);
+ }
+
}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
index d60e1f1..d271a28 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
@@ -85,6 +85,15 @@
return success(true);
}
+ @DeleteMapping("/delete-list")
+ @Operation(summary = "鎵归噺鍒犻櫎鐗╂枡")
+ @Parameter(name = "ids", description = "缂栧彿鍒楄〃", required = true, example = "1,2,3")
+ @PreAuthorize("@ss.hasPermission('mdm:item:delete')")
+ public CommonResult<Boolean> deleteItemList(@RequestParam("ids") List<Long> ids) {
+ itemService.deleteItemList(ids);
+ return success(true);
+ }
+
@GetMapping("/get")
@Operation(summary = "鑾峰緱鐗╂枡")
@Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemService.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemService.java
index 7235c20..d5dfca7 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemService.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemService.java
@@ -50,6 +50,13 @@
void deleteItem(Long id);
/**
+ * 鎵归噺鍒犻櫎鐗╂枡
+ *
+ * @param ids 缂栧彿鍒楄〃
+ */
+ void deleteItemList(Collection<Long> ids);
+
+ /**
* 鑾峰緱鐗╂枡
*
* @param id 缂栧彿
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
index bea2631..5acea4b 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
@@ -187,6 +187,16 @@
}
@Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteItemList(Collection<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return;
+ }
+ // 閫愪釜鍒犻櫎锛堝鐢ㄥ崟鏉″垹闄ら�昏緫锛屼繚鎸佹牎楠岋級
+ ids.forEach(this::deleteItem);
+ }
+
+ @Override
public MdmItemDO validateItemExists(Long id) {
MdmItemDO item = itemMapper.selectById(id);
if (item == null) {
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApi.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApi.java
index b98ad92..a31475f 100644
--- a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApi.java
+++ b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApi.java
@@ -3,6 +3,7 @@
import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsCreateReqDTO;
import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsRespDTO;
+import java.math.BigDecimal;
import java.util.List;
/**
@@ -76,4 +77,23 @@
*/
MesProMpsRespDTO getMpsByWorkOrderId(Long workOrderId);
+ /**
+ * 鏇存柊 MPS 鐨勫凡鐢熶骇鏁伴噺锛堢疮鍔狅級
+ *
+ * @param mpsId MPS 缂栧彿
+ * @param quantity 澧炲姞鐨勬暟閲�
+ */
+ void updateMpsProducedQuantity(Long mpsId, BigDecimal quantity);
+
+ /**
+ * 妫�鏌ュ苟鑷姩瀹屾垚 MPS
+ *
+ * 濡傛灉 MPS 婊¤冻瀹屾垚鏉′欢锛堝凡鐢熶骇鏁伴噺 >= 璁″垝鏁伴噺 涓� 鎵�鏈夋姤宸ュ凡瀹屾垚锛夛紝
+ * 鍒欒嚜鍔ㄥ皢 MPS 鐘舵�佹洿鏂颁负宸插畬鎴�
+ *
+ * @param mpsId MPS 缂栧彿
+ * @return true=宸插畬鎴愭垨鏈鑷姩瀹屾垚锛宖alse=鏈畬鎴�
+ */
+ Boolean checkAndFinishMps(Long mpsId);
+
}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApiImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApiImpl.java
index 30aadce..cdf418a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApiImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApiImpl.java
@@ -11,6 +11,7 @@
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -106,4 +107,14 @@
return BeanUtils.toBean(mps, MesProMpsRespDTO.class);
}
+ @Override
+ public void updateMpsProducedQuantity(Long mpsId, BigDecimal quantity) {
+ mpsService.updateProducedQuantity(mpsId, quantity);
+ }
+
+ @Override
+ public Boolean checkAndFinishMps(Long mpsId) {
+ return mpsService.checkAndFinishMps(mpsId);
+ }
+
}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
index 096b440..7e1868e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
@@ -195,9 +195,14 @@
}
}
- // 4. 鍏抽敭宸ュ簭锛氱敓鎴愪骇鍑哄崟锛屽苟鏍规嵁鏄惁闇�瑕佹楠屽喅瀹氬叆搴撴柟寮�
+ // 5. 鍏堟洿鏂版姤宸ョ姸鎬佷负宸插畬鎴愶紙纭繚 checkAndFinishMps 妫�鏌ユ椂褰撳墠鎶ュ伐宸叉爣璁板畬鎴愶級
+ feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
+ .setStatus(MesProFeedbackStatusEnum.FINISHED.getStatus())
+ .setUncheckQuantity(BigDecimal.ZERO));
+
+ // 6. 鍏抽敭宸ュ簭锛氱敓鎴愪骇鍑哄崟锛屽苟鏍规嵁鏄惁闇�瑕佹楠屽喅瀹氬叆搴撴柟寮�
if (keyFlag) {
- // 4.1 闇�瑕佹楠岋細鐢熸垚浜у嚭鍗曪紙璐ㄩ噺鐘舵��=寰呮楠岋級锛屾洿鏂版姤宸ョ姸鎬佷负寰呮楠岋紝绛夎川妫�瀹屾垚鍥炶皟鍚庡啀鍏ュ簱
+ // 6.1 闇�瑕佹楠岋細鐢熸垚浜у嚭鍗曪紙璐ㄩ噺鐘舵��=寰呮楠岋級锛屾洿鏂版姤宸ョ姸鎬佷负寰呮楠岋紝绛夎川妫�瀹屾垚鍥炶皟鍚庡啀鍏ュ簱
if (checkFlag) {
// 瀹屾垚鏃跺洖璋冭锛歁esQcIpqcServiceImpl#finishIpqc 鈫� splitPendingAndFinishProduce + completeFeedbackFromIpqc
productProduceService.generateProductProduce(feedback, true);
@@ -205,22 +210,20 @@
.setStatus(MesProFeedbackStatusEnum.UNCHECK.getStatus()));
return false;
}
- // 4.2 鏃犻渶妫�楠岋細鐢熸垚浜у嚭鍗曪紙鎸夊悎鏍�/涓嶅悎鏍兼媶琛岋級锛岀洿鎺ュ畬鎴愬叆搴擄紝骞舵洿鏂颁换鍔�/宸ュ崟鐨勫凡鐢熶骇鏁伴噺
+ // 6.2 鏃犻渶妫�楠岋細鐢熸垚浜у嚭鍗曪紙鎸夊悎鏍�/涓嶅悎鏍兼媶琛岋級锛岀洿鎺ュ畬鎴愬叆搴擄紝骞舵洿鏂颁换鍔�/宸ュ崟鐨勫凡鐢熶骇鏁伴噺
MesWmProductProduceDO produce = productProduceService.generateProductProduce(feedback, false);
productProduceService.finishProductProduce(produce.getId());
updateTaskAndWorkOrderByFeedback(feedback);
} else {
- // 4.3 闈炲叧閿伐搴忥細鍙洿鏂颁换鍔$殑宸茬敓浜ф暟閲忥紙宸ュ崟涓嶆洿鏂帮紝宸ュ崟鍙湅鍏抽敭宸ュ簭浜у嚭锛�
+ // 6.3 闈炲叧閿伐搴忥細鍙洿鏂颁换鍔$殑宸茬敓浜ф暟閲忥紙宸ュ崟涓嶆洿鏂帮紝宸ュ崟鍙湅鍏抽敭宸ュ簭浜у嚭锛�
taskService.updateProducedQuantity(feedback.getTaskId(),
feedback.getFeedbackQuantity(),
ObjectUtil.defaultIfNull(feedback.getQualifiedQuantity(), BigDecimal.ZERO),
ObjectUtil.defaultIfNull(feedback.getUnqualifiedQuantity(), BigDecimal.ZERO));
+ // 6.4 闈炲叧閿伐搴忎篃闇�瑕佹鏌� MPS 瀹屾垚鐘舵�侊紙鎵�鏈夊伐搴忔姤宸ュ畬鎴愭墠绠楀畬鎴愶級
+ checkAndPublishProductionFinished(feedback.getWorkOrderId());
}
- // 5. 闈炲叧閿伐搴� / 鍏抽敭闈炶川妫�宸ュ簭锛氱洿鎺ュ畬鎴愶紙娓呴浂 uncheckQuantity 闃叉 !key+check 鐣欒剰鏁版嵁锛�
- feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
- .setStatus(MesProFeedbackStatusEnum.FINISHED.getStatus())
- .setUncheckQuantity(BigDecimal.ZERO));
return true; // 宸插畬鎴�
}
@@ -256,7 +259,13 @@
workOrderService.updateProducedQuantity(feedback.getWorkOrderId(),
feedback.getFeedbackQuantity());
- // 4. 妫�鏌ュ苟鍙戝竷鐢熶骇瀹屾垚浜嬩欢
+ // 4. 鏇存柊 MPS 鐨勫凡鐢熶骇鏁伴噺锛堝鏋滄槸閿�鍞鍗曟潵婧愶級
+ MesProMpsRespDTO mps = mpsApi.getMpsByWorkOrderId(feedback.getWorkOrderId());
+ if (mps != null) {
+ mpsApi.updateMpsProducedQuantity(mps.getId(), feedback.getFeedbackQuantity());
+ }
+
+ // 5. 妫�鏌ュ苟鍙戝竷鐢熶骇瀹屾垚浜嬩欢
checkAndPublishProductionFinished(feedback.getWorkOrderId());
}
@@ -270,7 +279,10 @@
return; // 闈為攢鍞鍗曟潵婧愮殑宸ュ崟锛岃烦杩�
}
- // 2. 妫�鏌ラ攢鍞鍗曟墍鏈夌敓浜ф槸鍚﹀畬鎴�
+ // 2. 妫�鏌ュ苟鑷姩瀹屾垚 MPS锛堝鏋滄弧瓒虫潯浠讹級
+ mpsApi.checkAndFinishMps(mps.getId());
+
+ // 3. 妫�鏌ラ攢鍞鍗曟墍鏈夌敓浜ф槸鍚﹀畬鎴�
if (mpsApi.checkSaleOrderProductionFinished(mps.getSaleOrderId())) {
eventPublisher.publishEvent(new ProductionFinishedEvent(mps.getSaleOrderId(), java.time.LocalDateTime.now()));
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsService.java
index e1fa3e4..63e382d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsService.java
@@ -165,4 +165,15 @@
*/
MesProMpsDO getMpsByWorkOrderId(Long workOrderId);
+ /**
+ * 妫�鏌ュ苟鑷姩瀹屾垚 MPS
+ *
+ * 濡傛灉 MPS 婊¤冻瀹屾垚鏉′欢锛堝凡鐢熶骇鏁伴噺 >= 璁″垝鏁伴噺 涓� 鎵�鏈夋姤宸ュ凡瀹屾垚锛夛紝
+ * 鍒欒嚜鍔ㄥ皢 MPS 鐘舵�佹洿鏂颁负宸插畬鎴�
+ *
+ * @param mpsId MPS 缂栧彿
+ * @return true=宸插畬鎴愭垨鏈鑷姩瀹屾垚锛宖alse=鏈畬鎴�
+ */
+ Boolean checkAndFinishMps(Long mpsId);
+
}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
index 2ddacaf..a707cf5 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
@@ -365,6 +365,40 @@
return mpsMapper.selectOne(MesProMpsDO::getWorkOrderId, workOrderId);
}
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean checkAndFinishMps(Long mpsId) {
+ if (mpsId == null) {
+ log.warn("[checkAndFinishMps] mpsId is null");
+ return false;
+ }
+ MesProMpsDO mps = mpsMapper.selectById(mpsId);
+ if (mps == null) {
+ log.warn("[checkAndFinishMps] MPS not found, mpsId={}", mpsId);
+ return false;
+ }
+ // 宸插畬鎴愭垨宸插彇娑堬紝鐩存帴杩斿洖 true
+ if (MesProMpsStatusEnum.FINISHED.getStatus().equals(mps.getStatus())
+ || MesProMpsStatusEnum.CANCELED.getStatus().equals(mps.getStatus())) {
+ log.info("[checkAndFinishMps] MPS {} already finished or canceled, status={}", mpsId, mps.getStatus());
+ return true;
+ }
+ // 妫�鏌ユ槸鍚︽弧瓒冲畬鎴愭潯浠�
+ boolean finished = isMpsFinished(mps);
+ log.info("[checkAndFinishMps] MPS {} check result: {}, quantity={}, produced={}, workOrderId={}",
+ mpsId, finished, mps.getQuantity(), mps.getQuantityProduced(), mps.getWorkOrderId());
+ if (finished) {
+ // 鑷姩瀹屾垚 MPS
+ mpsMapper.updateById(new MesProMpsDO()
+ .setId(mpsId)
+ .setStatus(MesProMpsStatusEnum.FINISHED.getStatus())
+ .setFinishDate(LocalDateTime.now()));
+ log.info("[checkAndFinishMps] MPS {} auto finished", mpsId);
+ return true;
+ }
+ return false;
+ }
+
/**
* 鍒ゆ柇鍗曚釜 MPS 鏄惁瀹屾垚
*/
@@ -372,6 +406,8 @@
// 1. 宸茬敓浜ф暟閲� >= 璁″垝鏁伴噺
BigDecimal quantityProduced = ObjUtil.defaultIfNull(mps.getQuantityProduced(), BigDecimal.ZERO);
if (quantityProduced.compareTo(mps.getQuantity()) < 0) {
+ log.debug("[isMpsFinished] MPS {} quantity not enough: produced={}, required={}",
+ mps.getId(), quantityProduced, mps.getQuantity());
return false;
}
// 2. 妫�鏌ュ伐鍗曚笅鎵�鏈夋姤宸ユ槸鍚﹀畬鎴愶紙纭繚璐ㄦ瀹屾垚锛�
@@ -380,6 +416,7 @@
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MesProFeedbackDO>()
.eq(MesProFeedbackDO::getWorkOrderId, mps.getWorkOrderId())
.ne(MesProFeedbackDO::getStatus, MesProFeedbackStatusEnum.FINISHED.getStatus()));
+ log.debug("[isMpsFinished] MPS {} unfinished feedback count: {}", mps.getId(), unfinishedCount);
if (unfinishedCount > 0) {
return false;
}
--
Gitblit v1.9.3