From 6291e5799cf5165cd966a3923b1c70e2cd2621a8 Mon Sep 17 00:00:00 2001
From: cuilei <ray_tsu1@163.com>
Date: 星期五, 30 五月 2025 22:35:00 +0800
Subject: [PATCH] 工具管理-增加出库申请提交锁库、审批驳回释放锁库逻辑

---
 lxzn-module-tms/src/main/java/org/jeecg/modules/tms/service/impl/OutboundOrderServiceImpl.java |  595 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 581 insertions(+), 14 deletions(-)

diff --git a/lxzn-module-tms/src/main/java/org/jeecg/modules/tms/service/impl/OutboundOrderServiceImpl.java b/lxzn-module-tms/src/main/java/org/jeecg/modules/tms/service/impl/OutboundOrderServiceImpl.java
index 70bb424..221f064 100644
--- a/lxzn-module-tms/src/main/java/org/jeecg/modules/tms/service/impl/OutboundOrderServiceImpl.java
+++ b/lxzn-module-tms/src/main/java/org/jeecg/modules/tms/service/impl/OutboundOrderServiceImpl.java
@@ -2,32 +2,50 @@
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.subject.Subject;
+import org.flowable.engine.TaskService;
+import org.flowable.task.api.Task;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+import org.jeecg.modules.flowable.apithird.business.service.IFlowMyBusinessService;
+import org.jeecg.modules.flowable.apithird.service.FlowCallBackServiceI;
+import org.jeecg.modules.flowable.apithird.service.FlowCommonService;
+import org.jeecg.modules.flowable.service.IFlowDefinitionService;
+import org.jeecg.modules.flowable.service.IFlowTaskService;
 import org.jeecg.modules.system.service.ISysBusinessCodeRuleService;
-import org.jeecg.modules.tms.entity.OutboundOrder;
-import org.jeecg.modules.tms.entity.OutboundDetail;
+import org.jeecg.modules.tms.entity.*;
+import org.jeecg.modules.tms.entity.dto.OutBoundAddDto;
+import org.jeecg.modules.tms.entity.dto.OutBoundOrderFlowDto;
+import org.jeecg.modules.tms.entity.dto.OutBoundRequestDto;
 import org.jeecg.modules.tms.entity.dto.OutboundOrderAndDetailDto;
 import org.jeecg.modules.tms.enums.OutBillStatus;
+import org.jeecg.modules.tms.enums.OutBoundStatusEnum;
+import org.jeecg.modules.tms.enums.OutStorehouseType;
+import org.jeecg.modules.tms.enums.ToolCirculationStatus;
 import org.jeecg.modules.tms.mapper.OutboundDetailMapper;
+import org.jeecg.modules.tms.convert.OutboundOrderConvert;
 import org.jeecg.modules.tms.mapper.OutboundOrderMapper;
-import org.jeecg.modules.tms.service.IOutboundDetailService;
-import org.jeecg.modules.tms.service.IOutboundOrderService;
+import org.jeecg.modules.tms.service.*;
 import org.springframework.stereotype.Service;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import java.io.Serializable;
-import java.util.List;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Objects;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @Description: tms_outbound_order
@@ -35,13 +53,32 @@
  * @Date:   2025-05-16
  * @Version: V1.0
  */
+@Slf4j
 @Service
-public class OutboundOrderServiceImpl extends ServiceImpl<OutboundOrderMapper, OutboundOrder> implements IOutboundOrderService {
+public class OutboundOrderServiceImpl extends ServiceImpl<OutboundOrderMapper, OutboundOrder> implements IOutboundOrderService, FlowCallBackServiceI {
 
 	@Autowired
 	private IOutboundDetailService outboundDetailService;
 	@Autowired
+	private IToolLedgerService toolLedgerService;
+	@Autowired
+	private IToolLedgerDetailService toolLedgerDetailService;
+	@Autowired
+	private IOutStoreDetailService outStoreDetailService;
+	@Autowired
+	private IBaseToolsService baseToolsService;
+	@Autowired
 	private ISysBusinessCodeRuleService businessCodeRuleService;
+	@Autowired
+	private IFlowDefinitionService flowDefinitionService;
+	@Autowired
+	private IFlowMyBusinessService flowMyBusinessService;
+	@Autowired
+	private IFlowTaskService flowTaskService;
+	@Autowired
+	private TaskService taskService;
+	@Autowired
+	private FlowCommonService flowCommonService;
 	@Autowired
 	private OutboundOrderMapper outboundOrderMapper;
 	@Autowired
@@ -66,13 +103,14 @@
     @Override
 	@Transactional(rollbackFor = Exception.class)
     public void addTotal(OutboundOrderAndDetailDto outboundOrder) {
-		OutboundOrder order = BeanUtil.copyProperties(outboundOrder, OutboundOrder.class);
+		OutboundOrder order = OutboundOrderConvert.INSTANCE.convert(outboundOrder);
 		order.setHandler(Objects.requireNonNull(getCurrentUser()).getId());
 		order.setOutNum(businessCodeRuleService.generateBusinessCodeSeq("outBoundOrder"));
 		order.setOrderStatus(OutBillStatus.DRAFT.getValue());
 		save(order);
 		List<OutboundDetail> detailList = CollectionUtil.newArrayList();
 		outboundOrder.getOutboundDetailList().forEach(item->{
+			item.setId(null);
 			item.setOutStorehouseId(order.getId());
 			detailList.add(item);
 		});
@@ -90,9 +128,14 @@
 		if (outStorehouseTypes != null && outStorehouseTypes.length > 0) {
 			queryWrapper.eq("t.out_storehouse_type", outStorehouseTypes[0]);
 		}
-		String[] statuses = parameterMap.get("orderStatus");
-		if (statuses != null && statuses.length > 0) {
-			queryWrapper.eq("t.order_status", statuses[0]);
+		String[] orderStatuses = parameterMap.get("orderStatus");
+		if (orderStatuses != null && orderStatuses.length > 0) {
+			queryWrapper.eq("t.order_status", orderStatuses[0]);
+		}
+		String[] outStatuses = parameterMap.get("outStatus");
+		if (outStatuses != null && outStatuses.length > 0) {
+			String[] statusArr = outStatuses[0].split(",");
+			queryWrapper.in("t.out_status", statusArr);
 		}
 		String[] startTimes = parameterMap.get("startTime");
 		if (startTimes != null && startTimes.length > 0) {
@@ -122,7 +165,471 @@
 		outboundDetailService.saveBatch(detailList);
 	}
 
-	private LoginUser getCurrentUser() {
+    @Override
+	@Transactional(rollbackFor = Exception.class)
+    public void submit(String id) {
+		OutboundOrder outboundOrder = getById(id);
+		if (outboundOrder == null) {
+			throw new JeecgBootException("鍑哄簱鍗曠敵璇峰崟涓嶅瓨鍦紝鏃犳硶鎻愪氦锛�");
+		}
+		if (!Objects.equals(outboundOrder.getOrderStatus(), OutBillStatus.DRAFT.getValue())) {
+			throw new JeecgBootException("鏃犳硶鎻愪氦闈炶崏绋跨姸鎬佺殑鍑哄簱鐢宠鍗曪紒");
+		}
+		//閿佸畾鐢宠鍗曟槑缁嗕腑宸ュ叿搴撳瓨
+		if (lockOutboundStock(id)) {
+			//鍚姩娴佺▼
+			if (triggerProcess(outboundOrder)) {
+				outboundOrder.setOrderStatus(OutBillStatus.SUBMITTED.getValue());
+				updateById(outboundOrder);
+			}
+		}
+    }
+
+	private boolean lockOutboundStock(String id) {
+		List<OutboundDetail> outboundDetailList = outboundDetailService.list(new LambdaQueryWrapper<OutboundDetail>()
+				.eq(OutboundDetail::getOutStorehouseId, id));
+
+		LambdaQueryWrapper<ToolLedgerDetail> queryWrapper = new LambdaQueryWrapper<>();
+		for (int i = 0; i < outboundDetailList.size(); i++) {
+			if (i > 0) {
+				queryWrapper.or();
+			}
+			OutboundDetail detail = outboundDetailList.get(i);
+			queryWrapper.or(wrapper ->
+					wrapper.eq(StrUtil.isNotBlank(detail.getToolCode()), ToolLedgerDetail::getToolCode, detail.getToolCode())
+							.eq(StrUtil.isNotBlank(detail.getToolId()), ToolLedgerDetail::getToolId, detail.getToolId()) //濡傛灉涓嶇鍒版妸锛岃瀛楁涓虹┖
+			);
+		}
+		List<ToolLedgerDetail> toolLedgerDetailList = toolLedgerDetailService.list(queryWrapper);
+		List<ToolLedgerDetail> toolLedgerDetailUpdateList = CollectionUtil.newArrayList();
+		for (OutboundDetail detail : outboundDetailList) {
+			String toolCode = detail.getToolCode();
+			List<ToolLedgerDetail> ledgerDetailList = toolLedgerDetailList.stream().filter(item -> Objects.equals(item.getToolCode(), toolCode)
+					&& Objects.equals(item.getToolId(), detail.getToolId())).collect(Collectors.toList());
+			if (CollectionUtil.isEmpty(ledgerDetailList)) {
+				BaseTools tools = baseToolsService.getById(toolCode);
+				throw new JeecgBootException("缂栫爜涓恒��" + tools.getToolCode() + "銆戠殑宸ュ叿锛屽簱瀛樹笉瓒筹紒");
+			} else {
+				ToolLedgerDetail toolLedgerDetail = ledgerDetailList.get(0);
+				if (toolLedgerDetail.getQuantity().compareTo(detail.getOutboundQuantity()) < 0) {
+					throw new JeecgBootException("缂栫爜涓恒��" + toolLedgerDetail.getToolCode() + "銆戠殑宸ュ叿锛屽簱瀛樹笉瓒筹紒");
+				} else {
+					//鎵e噺鍙拌处鏄庣粏涓殑搴撳瓨锛屾墽琛岄攣搴�
+					if (StrUtil.isBlank(detail.getToolId())) {
+						//绠″埌绫荤殑鍒�鍏�
+						toolLedgerDetail.setQuantity(toolLedgerDetail.getQuantity().subtract(detail.getOutboundQuantity()));
+					} else {
+						//绠″埌鎶婄殑鍒�鍏凤紝鏁伴噺鍙湁 0鍜�1
+						toolLedgerDetail.setQuantity(BigDecimal.ZERO);
+					}
+					toolLedgerDetailUpdateList.add(toolLedgerDetail);
+				}
+			}
+		}
+
+		Map<String, BigDecimal> outToolCodeQuantityMap = outboundDetailList.stream().collect(Collectors.groupingBy(OutboundDetail::getToolCode,
+				Collectors.mapping(OutboundDetail::getOutboundQuantity, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
+		Map<String, ToolLedger> toolLedgerMap = toolLedgerService.list(new LambdaQueryWrapper<ToolLedger>().in(ToolLedger::getToolId, outToolCodeQuantityMap.keySet()))
+				.stream().collect(Collectors.toMap(ToolLedger::getToolId, toolLedger -> toolLedger, (k1, k2) -> k1));
+		List<ToolLedger> toolLedgerUpdateList = CollectionUtil.newArrayList();
+		for (String toolCode : outToolCodeQuantityMap.keySet()) {
+			BigDecimal outQuantity = outToolCodeQuantityMap.get(toolCode);
+			ToolLedger toolLedger = toolLedgerMap.get(toolCode);
+			BaseTools tools = baseToolsService.getById(toolCode);
+			if (Objects.isNull(toolLedger) || toolLedger.getAvailableCount().compareTo(outQuantity) < 0) {
+				throw new JeecgBootException("缂栫爜涓恒��" + tools.getToolCode() + "銆戠殑宸ュ叿锛屽簱瀛樹笉瓒筹紒");
+			} else {
+				//鎵e噺鍙拌处涓昏〃涓殑鍙敤瀛樺簱锛屾墽琛岄攣搴�
+				toolLedger.setAvailableCount(toolLedger.getAvailableCount().subtract(outQuantity));
+				toolLedgerUpdateList.add(toolLedger);
+			}
+		}
+		toolLedgerDetailService.updateBatchById(toolLedgerDetailUpdateList);
+		toolLedgerService.updateBatchById(toolLedgerUpdateList);
+		return true;
+	}
+
+	@Transactional(rollbackFor = Exception.class)
+	@Override
+	public void approvalProcess(OutBoundOrderFlowDto outBoundOrderFlowDto) {
+		if (StrUtil.isBlank(outBoundOrderFlowDto.getTaskId()) || StrUtil.isBlank(outBoundOrderFlowDto.getDataId())) {
+			throw new JeecgBootException("闈炴硶鍙傛暟锛�");
+		}
+
+		// 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛
+		LoginUser user = getCurrentUser();
+		if (user == null || StrUtil.isBlank(user.getId())) {
+			throw new JeecgBootException("璐﹀彿涓嶅瓨鍦�");
+		}
+
+		//鑾峰彇鍑哄簱鐢宠鍗曚俊鎭�
+		OutboundOrder outboundOrder = getById(outBoundOrderFlowDto.getDataId());
+		if (outboundOrder == null) {
+			throw new JeecgBootException("鏈壘鍒板搴旂殑鍑哄簱鐢宠鍗曪紒");
+		}
+
+		//鑾峰彇娴佺▼涓氬姟璁板綍
+		FlowMyBusiness flowMyBusiness = getFlowMyBusiness(outBoundOrderFlowDto.getInstanceId());
+		if (flowMyBusiness == null) {
+			throw new JeecgBootException("娴佺▼璁板綍涓嶅瓨鍦�");
+		}
+
+		// 妫�鏌ョ敤鎴锋槸鍚︽湁鏉冮檺鎿嶄綔浠诲姟
+		if (!isUserAuthorized(flowMyBusiness, user)) {
+			throw new JeecgBootException("鐢ㄦ埛鏃犳潈鎿嶄綔姝や换鍔�");
+		}
+
+		// 璁ら浠诲姟
+		if (!claimTask(flowMyBusiness.getTaskId(), user)) {
+			throw new JeecgBootException("浠诲姟涓嶅瓨鍦ㄣ�佸凡瀹屾垚鎴栧凡琚粬浜鸿棰�");
+		}
+
+		//璁剧疆娴佺▼鍙橀噺
+		setupProcessVariables(outBoundOrderFlowDto, outboundOrder, user);
+
+		//瀹屾垚娴佺▼浠诲姟
+		Result result = flowTaskService.complete(outBoundOrderFlowDto);
+
+		//鏍规嵁浠诲姟瀹屾垚缁撴灉鏇存柊鐢宠鍗曠姸鎬�
+		if (result.isSuccess()) {
+			if (OutBillStatus.APPROVED.getValue().equals(outBoundOrderFlowDto.getStatus())) {
+				outboundOrder.setOutStatus(OutBoundStatusEnum.NOT_OUTBOUND.getValue());
+				outboundOrder.setOrderStatus(OutBillStatus.APPROVED.getValue());
+				//鍒濆鍖栫敵璇锋槑缁嗕俊鎭殑鍑哄簱鐘舵��/瀹為檯鍑哄簱鏁伴噺瀛楁
+				outboundDetailService.update(new LambdaUpdateWrapper<OutboundDetail>()
+						.eq(OutboundDetail::getOutStorehouseId, outboundOrder.getId())
+						.set(OutboundDetail::getStatus, OutBoundStatusEnum.NOT_OUTBOUND.getValue())
+						.set(OutboundDetail::getOutActualCount, BigDecimal.ZERO));
+			}
+			if (OutBillStatus.REJECTED.getValue().equals(outBoundOrderFlowDto.getStatus())) {
+				//濡傛灉椹冲洖锛屽鎵瑰崟鐘舵�佸洖鍒拌崏绋�
+				outboundOrder.setOrderStatus(OutBillStatus.DRAFT.getValue());
+				//閲婃斁鐢宠鍗曚腑閿佸畾鐨勫簱瀛�
+				releaseStock(outboundOrder);
+			}
+			outboundOrder.setAuditDate(new Date());
+			outboundOrder.setApprovalOpinion(outBoundOrderFlowDto.getApprovalOpinion());
+			updateById(outboundOrder);
+		}
+	}
+
+	private void releaseStock(OutboundOrder outboundOrder) {
+		List<OutboundDetail> outboundDetailList = outboundDetailService.list(new LambdaQueryWrapper<OutboundDetail>()
+				.eq(OutboundDetail::getOutStorehouseId, outboundOrder.getId()));
+
+		LambdaQueryWrapper<ToolLedgerDetail> queryWrapper = new LambdaQueryWrapper<>();
+		for (int i = 0; i < outboundDetailList.size(); i++) {
+			if (i > 0) {
+				queryWrapper.or();
+			}
+			OutboundDetail detail = outboundDetailList.get(i);
+			queryWrapper.or(wrapper ->
+					wrapper.eq(StrUtil.isNotBlank(detail.getToolCode()), ToolLedgerDetail::getToolCode, detail.getToolCode())
+							.eq(StrUtil.isNotBlank(detail.getToolId()), ToolLedgerDetail::getToolId, detail.getToolId()) //濡傛灉涓嶇鍒版妸锛岃瀛楁涓虹┖
+			);
+		}
+		List<ToolLedgerDetail> toolLedgerDetailList = toolLedgerDetailService.list(queryWrapper);
+		List<ToolLedgerDetail> toolLedgerDetailUpdateList = CollectionUtil.newArrayList();
+		for (OutboundDetail detail : outboundDetailList) {
+			Optional<ToolLedgerDetail> optonal = toolLedgerDetailList.stream().filter(item -> Objects.equals(item.getToolCode(), detail.getToolCode())
+					&& Objects.equals(item.getToolId(), detail.getToolId())).findFirst();
+			if (optonal.isPresent()) {
+				ToolLedgerDetail toolLedgerDetail = optonal.get();
+				if (StrUtil.isBlank(detail.getToolId())) {
+					//鍒扮被
+					toolLedgerDetail.setQuantity(toolLedgerDetail.getQuantity().add(detail.getOutboundQuantity()));
+				} else {
+					//鍒版妸
+					toolLedgerDetail.setQuantity(BigDecimal.ONE);
+				}
+				toolLedgerDetailUpdateList.add(toolLedgerDetail);
+			}
+		}
+
+		Map<String, BigDecimal> outToolCodeQuantityMap = outboundDetailList.stream().collect(Collectors.groupingBy(OutboundDetail::getToolCode,
+				Collectors.mapping(OutboundDetail::getOutboundQuantity, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
+		Map<String, ToolLedger> toolLedgerMap = toolLedgerService.list(new LambdaQueryWrapper<ToolLedger>().in(ToolLedger::getToolId, outToolCodeQuantityMap.keySet()))
+				.stream().collect(Collectors.toMap(ToolLedger::getToolId, toolLedger -> toolLedger, (k1, k2) -> k1));
+		List<ToolLedger> toolLedgerUpdateList = new ArrayList<>();
+		for (String baseToolId : outToolCodeQuantityMap.keySet()) {
+			BigDecimal outQuantity = outToolCodeQuantityMap.get(baseToolId);
+			ToolLedger toolLedger = toolLedgerMap.get(baseToolId);
+			if (Objects.nonNull(toolLedger)) {
+				toolLedger.setAvailableCount(toolLedger.getAvailableCount().add(outQuantity));
+				toolLedgerUpdateList.add(toolLedger);
+			}
+		}
+		toolLedgerDetailService.updateBatchById(toolLedgerDetailUpdateList);
+		toolLedgerService.updateBatchById(toolLedgerUpdateList);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void outBoundByApply(List<OutBoundRequestDto> outBoundRequestList) {
+		//鏍¢獙鏄惁鏉ヨ嚜涓�涓敵璇峰崟
+		if (!fromOneApply(outBoundRequestList)) {
+			throw new JeecgBootException("鍑哄簱鏄庣粏蹇呴』鏉ヨ嚜鍚屼竴鍑哄簱鐢宠鍗曪紒");
+		}
+		//鏄惁鍙嚭搴撴牎楠�
+		if (!readyToOutbound(outBoundRequestList)) {
+			throw new JeecgBootException("鏈粡瀹℃壒閫氳繃鐨勭敵璇峰崟涓嶈兘鍑哄簱锛�");
+		}
+		//寮�濮嬪嚭搴�
+		OutboundOrder outboundOrder = getById(outBoundRequestList.get(0).getOutBoundOrderId());
+		List<String> detailIds = outBoundRequestList.stream().map(OutBoundRequestDto::getOutboundDetailId).collect(Collectors.toList());
+		List<OutboundDetail> outboundDetailList = outboundDetailService.listByIds(detailIds);
+		List<String> toolIdList = outboundDetailList.stream().map(OutboundDetail::getToolCode).collect(Collectors.toList());
+
+		Map<String, BigDecimal> outBoundRequestMap = outBoundRequestList.stream()
+				.collect(Collectors.toMap(OutBoundRequestDto::getOutboundDetailId, OutBoundRequestDto::getOutboundQuantity));
+		//澶勭悊搴撳瓨鍙拌处鍙婂彴璐︽槑缁�
+		Map<String, ToolLedger> toolLedgerMap = toolLedgerService.list(new LambdaQueryWrapper<ToolLedger>().in(ToolLedger::getToolId, toolIdList)).stream()
+				.collect(Collectors.toMap(ToolLedger::getToolId, item -> item, (k1, k2) -> k1));
+
+		LambdaQueryWrapper<ToolLedgerDetail> queryWrapper = new LambdaQueryWrapper<>();
+		for (int i = 0; i < outboundDetailList.size(); i++) {
+			if (i > 0) {
+				queryWrapper.or();
+			}
+			OutboundDetail detail = outboundDetailList.get(i);
+			queryWrapper.or(wrapper ->
+					wrapper.eq(ToolLedgerDetail::getToolCode, detail.getToolCode())
+							.eq(ToolLedgerDetail::getToolId, detail.getToolId()) //濡傛灉涓嶇鍒版妸锛岃瀛楁涓虹┖
+			);
+		}
+		List<ToolLedgerDetail> toolLedgerDetailList = toolLedgerDetailService.list(queryWrapper);
+		List<ToolLedger> toolLedgerUpdateList = CollectionUtil.newArrayList();
+		List<ToolLedgerDetail> toolLedgerDetailUpdateList = CollectionUtil.newArrayList();
+		List<OutStoreDetail> outStoreAddList = CollectionUtil.newArrayList();
+		List<OutboundDetail> outboundDetailUpdateList = CollectionUtil.newArrayList();
+
+		for (OutboundDetail detail : outboundDetailList) {
+			//鏇存柊搴撳瓨鍙拌处
+			ToolLedger toolLedger = toolLedgerMap.get(detail.getToolCode());
+			BigDecimal outboundQuantity = outBoundRequestMap.get(detail.getId());
+			OutStorehouseType outStorehouseType = OutStorehouseType.getByValue(outboundOrder.getOutStorehouseType());
+			switch (outStorehouseType) {
+				case TOOL_BORROW:
+					toolLedger.setLendCount(toolLedger.getLendCount().add(outboundQuantity));
+					break;
+				case MAINTENANCE_OUTBOUND:
+					toolLedger.setRepairCount(toolLedger.getRepairCount().add(outboundQuantity));
+					break;
+				case CALIBRATION_OUTBOUND:
+					toolLedger.setDetectionCount(toolLedger.getDetectionCount().add(outboundQuantity));
+					break;
+				case GRINDING_OUTBOUND:
+					toolLedger.setSharpeningCount(toolLedger.getSharpeningCount().add(outboundQuantity));
+					break;
+				default:
+					throw new JeecgBootException("鏈煡鐨勫嚭搴撶被鍨嬶紒");
+			}
+			toolLedgerUpdateList.add(toolLedger);
+
+			//鏇存柊鍙拌处鏄庣粏
+			toolLedgerDetailList.stream().filter(item -> item.getToolCode().equals(detail.getToolCode()) && item.getToolId().equals(detail.getToolId()))
+					.findFirst().ifPresent(item -> {
+						switch (outStorehouseType) {
+							case TOOL_BORROW:
+								item.setStatus(ToolCirculationStatus.BORROWED.getValue());
+								break;
+							case MAINTENANCE_OUTBOUND:
+								item.setStatus(ToolCirculationStatus.REPAIRING.getValue());
+								break;
+							case CALIBRATION_OUTBOUND:
+								item.setStatus(ToolCirculationStatus.INSPECTING.getValue());
+								break;
+							case GRINDING_OUTBOUND:
+								item.setStatus(ToolCirculationStatus.GRINDING.getValue());
+								break;
+							default:
+								throw new JeecgBootException("鏈煡鐨勫嚭搴撶被鍨嬶紒");
+						}
+						toolLedgerDetailUpdateList.add(item);
+					});
+
+			//璁板綍鍑哄簱娴佹按
+			OutStoreDetail outStoreDetail = new OutStoreDetail()
+					.setToolCode(detail.getToolCode())
+					.setToolId(detail.getToolId())
+					.setOutStorehouseType(outboundOrder.getOutStorehouseType())
+					.setGoodsShelvesCode(detail.getOutboundLocation())
+					.setOutNumber(outboundQuantity)
+					.setOutStorehouseId(outboundOrder.getId())
+					.setOperateType("1");//1锛氭寜鐢宠鍗�
+			outStoreAddList.add(outStoreDetail);
+
+			//鏇存柊鐢宠鍗曟槑缁�
+			detail.setOutActualCount(detail.getOutActualCount().add(outboundQuantity));
+			detail.setOutboundTime(new Date());
+			if (detail.getOutActualCount().compareTo(detail.getOutboundQuantity()) == 0) {
+				detail.setStatus(OutBoundStatusEnum.COMPLETED.getValue());
+			} else {
+				detail.setStatus(OutBoundStatusEnum.PARTIAL_OUTBOUND.getValue());
+			}
+			outboundDetailUpdateList.add(detail);
+		}
+		toolLedgerService.updateBatchById(toolLedgerUpdateList);
+		toolLedgerDetailService.updateBatchById(toolLedgerDetailUpdateList);
+		outStoreDetailService.saveBatch(outStoreAddList);
+		outboundDetailService.updateBatchById(outboundDetailUpdateList);
+
+		//鏇存柊鐢宠鍗�
+		boolean allMatch = outboundDetailService.list(new LambdaQueryWrapper<OutboundDetail>()
+						.eq(OutboundDetail::getOutStorehouseId, outboundOrder.getId()))
+				.stream().filter(i -> !detailIds.contains(i.getId()))
+				.allMatch(i -> i.getStatus().equals(OutBoundStatusEnum.COMPLETED.getValue()));
+		List<OutboundDetail> partialOutboundList = outboundDetailUpdateList.stream()
+				.filter(i -> !i.getStatus().equals(OutBoundStatusEnum.COMPLETED.getValue())).collect(Collectors.toList());
+		if (allMatch && partialOutboundList.isEmpty()) {
+			outboundOrder.setOutStatus(OutBoundStatusEnum.COMPLETED.getValue());
+		} else {
+			outboundOrder.setOutStatus(OutBoundStatusEnum.PARTIAL_OUTBOUND.getValue());
+		}
+		outboundOrder.setOutboundTime(new Date());
+		updateById(outboundOrder);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void outBoundByAdd(List<OutBoundAddDto> boundAddList) {
+		//鏍¢獙鍙拌处涓昏〃搴撳瓨鏁伴噺
+		Map<String, BigDecimal> toolBoundQuantityMap = boundAddList.stream()
+				.collect(Collectors.groupingBy(OutBoundAddDto::getToolCode,
+						Collectors.mapping(OutBoundAddDto::getOutboundQuantity, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
+		Map<String, ToolLedger> toolLedgerMap = toolLedgerService.list(new LambdaQueryWrapper<ToolLedger>().in(ToolLedger::getToolId, toolBoundQuantityMap.keySet()))
+				.stream().collect(Collectors.toMap(ToolLedger::getToolId, item -> item, (k1, k2) -> k1));
+		List<ToolLedger> toolLedgerUpdateList = CollectionUtil.newArrayList();
+		for (String toolCode : toolBoundQuantityMap.keySet()) {
+			ToolLedger toolLedger = toolLedgerMap.get(toolCode);
+			BigDecimal outBoundQuantity = toolBoundQuantityMap.get(toolCode);
+			if (Objects.isNull(toolLedger) || toolLedger.getAvailableCount().compareTo(outBoundQuantity) < 0) {
+				BaseTools tools = baseToolsService.getById(toolCode);
+				throw new JeecgBootException("缂栫爜涓恒��" + tools.getToolCode() + "銆戠殑宸ュ叿锛屽簱瀛樹笉瓒筹紒");
+			} else {
+				OutStorehouseType outStorehouseType = OutStorehouseType.getByValue(boundAddList.get(0).getOutStorehouseType());
+				switch (outStorehouseType) {
+					case TOOL_BORROW:
+						toolLedger.setLendCount(toolLedger.getLendCount().add(outBoundQuantity));
+						break;
+					case MAINTENANCE_OUTBOUND:
+						toolLedger.setRepairCount(toolLedger.getRepairCount().add(outBoundQuantity));
+						break;
+					case CALIBRATION_OUTBOUND:
+						toolLedger.setDetectionCount(toolLedger.getDetectionCount().add(outBoundQuantity));
+						break;
+					case GRINDING_OUTBOUND:
+						toolLedger.setSharpeningCount(toolLedger.getSharpeningCount().add(outBoundQuantity));
+						break;
+					default:
+						throw new JeecgBootException("鏈煡鐨勫嚭搴撶被鍨嬶紒");
+				}
+				//鎵e噺鍙拌处涓昏〃鍙敤搴撳瓨
+				toolLedger.setAvailableCount(toolLedger.getAvailableCount().subtract(outBoundQuantity));
+				toolLedgerUpdateList.add(toolLedger);
+			}
+		}
+		//鏍¢獙鍙拌处鏄庣粏搴撳瓨鏁伴噺
+		Map<String, OutBoundAddDto> boundAddDtoMap = boundAddList.stream().collect(Collectors
+				.toMap(OutBoundAddDto::getToolLedgerDetailId, item -> item, (k1, k2) -> k1));
+		Map<String, ToolLedgerDetail> toolLedgerDetailMap = toolLedgerDetailService.listByIds(boundAddDtoMap.keySet()).stream()
+				.collect(Collectors.toMap(ToolLedgerDetail::getId, item -> item, (k1, k2) -> k1));
+		List<ToolLedgerDetail> toolLedgerDetailUpdateList = CollectionUtil.newArrayList();
+		for (String toolLedgerDetailId : boundAddDtoMap.keySet()) {
+			OutBoundAddDto outBoundAddDto = boundAddDtoMap.get(toolLedgerDetailId);
+			BigDecimal outboundQuantity = outBoundAddDto.getOutboundQuantity();
+			ToolLedgerDetail toolLedgerDetail = toolLedgerDetailMap.get(toolLedgerDetailId);
+			if (Objects.isNull(toolLedgerDetail) || toolLedgerDetail.getQuantity().compareTo(outboundQuantity) < 0) {
+				BaseTools tools = baseToolsService.getById(outBoundAddDto.getToolCode());
+				throw new JeecgBootException("缂栫爜涓恒��" + tools.getToolCode() + "銆戠殑宸ュ叿锛屽簱瀛樹笉瓒筹紒");
+			} else {
+				//鎵e噺鍙拌处鏄庣粏搴撳瓨
+				if (StrUtil.isBlank(toolLedgerDetail.getToolId())) {
+					//娌℃湁鍞竴缂栫爜锛屼笉绠″埌鎶婄殑
+					toolLedgerDetail.setQuantity(toolLedgerDetail.getQuantity().subtract(outboundQuantity));
+				} else {
+					//鏈夊敮涓�缂栫爜锛岀閬撴妸鐨�
+					toolLedgerDetail.setQuantity(BigDecimal.ZERO);//鏁伴噺鍙細鏄�0鍜�1
+					OutStorehouseType outStorehouseType = OutStorehouseType.getByValue(boundAddList.get(0).getOutStorehouseType());
+					switch (outStorehouseType) {
+						case TOOL_BORROW:
+							toolLedgerDetail.setStatus(ToolCirculationStatus.BORROWED.getValue());
+							break;
+						case MAINTENANCE_OUTBOUND:
+							toolLedgerDetail.setStatus(ToolCirculationStatus.REPAIRING.getValue());
+							break;
+						case CALIBRATION_OUTBOUND:
+							toolLedgerDetail.setStatus(ToolCirculationStatus.INSPECTING.getValue());
+							break;
+						case GRINDING_OUTBOUND:
+							toolLedgerDetail.setStatus(ToolCirculationStatus.GRINDING.getValue());
+							break;
+						default:
+							throw new JeecgBootException("鏈煡鐨勫嚭搴撶被鍨嬶紒");
+					}
+				}
+				toolLedgerDetailUpdateList.add(toolLedgerDetail);
+			}
+		}
+		toolLedgerService.updateBatchById(toolLedgerUpdateList);
+		toolLedgerDetailService.updateBatchById(toolLedgerDetailUpdateList);
+		//璁板綍鍑哄簱娴佹按
+		List<OutStoreDetail> outStoreAddList = CollectionUtil.newArrayList();
+		for (OutBoundAddDto outBoundAddDto : boundAddList) {
+			OutStoreDetail outStoreDetail = new OutStoreDetail()
+					.setToolCode(outBoundAddDto.getToolCode())
+					.setToolId(outBoundAddDto.getToolId())
+					.setOutStorehouseType(outBoundAddDto.getOutStorehouseType())
+					.setGoodsShelvesCode(outBoundAddDto.getOutboundLocation())
+					.setOutNumber(outBoundAddDto.getOutboundQuantity())
+					.setOperateType("2");//2锛氭墜宸ユ搷浣�
+			outStoreAddList.add(outStoreDetail);
+		}
+		outStoreDetailService.saveBatch(outStoreAddList);
+	}
+
+
+	private boolean fromOneApply(List<OutBoundRequestDto> outBoundRequestList) {
+		long count = outBoundRequestList.stream().map(OutBoundRequestDto::getOutBoundOrderId).distinct().count();
+		if (count > 1) {
+			return false;
+		}
+		List<String> outDetailIds = outBoundRequestList.stream().map(OutBoundRequestDto::getOutboundDetailId).collect(Collectors.toList());
+		String outboundDetailId = outBoundRequestList.get(0).getOutboundDetailId();
+		OutboundDetail outboundDetail = outboundDetailService.getById(outboundDetailId);
+		List<String> detailIds = outboundDetailService.list(new LambdaQueryWrapper<OutboundDetail>()
+				.eq(OutboundDetail::getOutStorehouseId, outboundDetail.getOutStorehouseId())).stream()
+				.map(OutboundDetail::getId).collect(Collectors.toList());
+        return new HashSet<>(detailIds).containsAll(outDetailIds);
+    }
+
+	private boolean readyToOutbound(List<OutBoundRequestDto> outBoundRequestList) {
+		String outBoundOrderId = outBoundRequestList.get(0).getOutBoundOrderId();
+		OutboundOrder outboundOrder = getById(outBoundOrderId);
+        return OutBillStatus.APPROVED.getValue().equals(outboundOrder.getOrderStatus());
+    }
+
+	public boolean triggerProcess(OutboundOrder outboundOrder) {
+		flowCommonService.initActBusiness("鍗曞彿涓猴細" + outboundOrder.getOutNum() + " 鐨勫嚭搴撶敵璇凤紝寮�濮嬭繘琛屽鎵�",
+				outboundOrder.getId(), "outboundOrderServiceImpl", "tool_out_storage", null);
+		Map<String, Object> variables = new HashMap<>();
+		variables.put("dataId", outboundOrder.getId());
+		if (StrUtil.isEmpty(outboundOrder.getRemark())) {
+			variables.put("organization", "鏂板鍑哄簱鐢宠鍗曢粯璁ゅ惎鍔ㄦ祦绋�");
+			variables.put("comment", "鏂板鍑哄簱鐢宠鍗曢粯璁ゅ惎鍔ㄦ祦绋�");
+		} else {
+			variables.put("organization", outboundOrder.getRemark());
+			variables.put("comment", outboundOrder.getRemark());
+		}
+		variables.put("proofreading", true);
+		List<String> usernames = new ArrayList<>();
+		usernames.add(outboundOrder.getReviewer());
+		variables.put("NextAssignee", usernames);
+		Result result = flowDefinitionService.startProcessInstanceByKey("tool_out_storage", variables);
+		return result.isSuccess();
+	}
+
+    private LoginUser getCurrentUser() {
 		// 鑾峰彇褰撳墠璁よ瘉鐨勭櫥褰曠敤鎴蜂俊鎭�
 		Subject currentUser = SecurityUtils.getSubject();
 		if (currentUser != null && currentUser.isAuthenticated()) {
@@ -133,4 +640,64 @@
 		}
 		return null;
 	}
+
+	private FlowMyBusiness getFlowMyBusiness(String instanceId) {
+		List<FlowMyBusiness> businessList = flowMyBusinessService.list(
+				new LambdaQueryWrapper<FlowMyBusiness>().eq(FlowMyBusiness::getProcessInstanceId, instanceId));
+		return businessList.isEmpty() ? null : businessList.get(0);
+	}
+
+	private boolean isUserAuthorized(FlowMyBusiness flowMyBusiness, LoginUser user) {
+		List<String> todoUsers = JSON.parseArray(flowMyBusiness.getTodoUsers(), String.class);
+		return todoUsers != null && todoUsers.contains(user.getUsername());
+	}
+
+	private boolean claimTask(String taskId, LoginUser user) {
+		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
+		if (task == null) {
+			return false;
+		}
+		if (task.getAssignee() != null && !task.getAssignee().equals(user.getUsername())) {
+			return false;
+		}
+		taskService.claim(taskId, user.getUsername());
+		return true;
+	}
+
+	private void setupProcessVariables(OutBoundOrderFlowDto outBoundOrderFlowDto, OutboundOrder outboundOrder, LoginUser user) {
+		if (OutBillStatus.SUBMITTED.getValue().equals(outboundOrder.getOrderStatus()) && user.getUsername().equals(outboundOrder.getReviewer())) {
+			Map<String, Object> values = new HashMap<>();
+			values.put("dataId", outboundOrder.getId());
+			values.put("organization", outBoundOrderFlowDto.getApprovalOpinion());
+			values.put("comment", outBoundOrderFlowDto.getApprovalOpinion());
+			values.put("status", outBoundOrderFlowDto.getStatus());
+			values.put("NextAssignee", Collections.singletonList(outboundOrder.getReviewer()));
+			outBoundOrderFlowDto.setValues(values);
+		}
+	}
+
+	@Override
+	public void afterFlowHandle(FlowMyBusiness business) {
+		business.getTaskNameId();//鎺ヤ笅鏉ュ鎵圭殑鑺傜偣
+		business.getValues();//鍓嶇浼犺繘鏉ョ殑鍙傛暟
+		business.getActStatus();
+	}
+
+	@Override
+	public Object getBusinessDataById(String dataId) {
+		return this.getById(dataId);
+	}
+
+	@Override
+	public Map<String, Object> flowValuesOfTask(String taskNameId, Map<String, Object> values) {
+		return Collections.emptyMap();
+	}
+
+	@Override
+	public List<String> flowCandidateUsernamesOfTask(String taskNameId, Map<String, Object> values) {
+		//涓氬姟鏄惁骞查娴佺▼锛屼笟鍔″共棰勶紝娴佺▼骞查锛屾寚瀹氫汉鍛樿繘琛屽鐞�
+		//鑾峰彇涓嬩竴姝ュ鐞嗕汉
+		Object object = values.get("NextAssignee");
+		return (List<String>) object;
+	}
 }

--
Gitblit v1.9.3