| New file |
| | |
| | | package com.zy.acs.manager.core.service; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.zy.acs.common.hk.state.HkState; |
| | | import com.zy.acs.common.hk.state.HkStateActionState; |
| | | import com.zy.acs.common.hk.state.type.HkActionStatusType; |
| | | import com.zy.acs.common.utils.RedisSupport; |
| | | import com.zy.acs.framework.common.Cools; |
| | | import com.zy.acs.manager.manager.entity.Action; |
| | | import com.zy.acs.manager.manager.entity.Segment; |
| | | import com.zy.acs.manager.manager.enums.ActionStsType; |
| | | import com.zy.acs.manager.manager.enums.SegmentStateType; |
| | | import com.zy.acs.manager.manager.service.ActionService; |
| | | import com.zy.acs.manager.manager.service.SegmentService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 海康 VDA state 闭环处理。 |
| | | * 仅复用现有结算逻辑,不改原有完成订阅逻辑。 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class HkOrderStateClosureService { |
| | | |
| | | private static final String HK_ORDER_COMPLETE_FLAG = "HK_AGV_ORDER_COMPLETE"; |
| | | |
| | | private static final int COMPLETE_MARK_EXPIRE_SECONDS = 7 * 24 * 60 * 60; |
| | | |
| | | private final RedisSupport redis = RedisSupport.defaultRedisSupport; |
| | | |
| | | @Autowired |
| | | private ActionService actionService; |
| | | @Autowired |
| | | private SegmentService segmentService; |
| | | @Autowired |
| | | private MainService mainService; |
| | | |
| | | @Transactional |
| | | public void process(HkState state) { |
| | | if (state == null || Cools.isEmpty(state.getOrderId())) { |
| | | return; |
| | | } |
| | | |
| | | syncFinishedActions(state); |
| | | |
| | | if (!isOrderCompleted(state)) { |
| | | return; |
| | | } |
| | | |
| | | settleCompletedOrder(state); |
| | | } |
| | | |
| | | private void syncFinishedActions(HkState state) { |
| | | if (Cools.isEmpty(state.getActionStates())) { |
| | | return; |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | String orderId = state.getOrderId(); |
| | | for (HkStateActionState actionState : state.getActionStates()) { |
| | | if (actionState == null || actionState.getActionStatus() != HkActionStatusType.FINISHED) { |
| | | continue; |
| | | } |
| | | |
| | | Long actionId = parseActionId(actionState.getActionId()); |
| | | if (actionId == null) { |
| | | continue; |
| | | } |
| | | |
| | | Action action = actionService.getOne(new LambdaQueryWrapper<Action>() |
| | | .eq(Action::getId, actionId) |
| | | .eq(Action::getGroupId, orderId) |
| | | .eq(Action::getActionSts, ActionStsType.ISSUED.val()) |
| | | .last("limit 1")); |
| | | if (action == null) { |
| | | continue; |
| | | } |
| | | |
| | | action.setActionSts(ActionStsType.FINISH.val()); |
| | | action.setEndTime(now); |
| | | action.setUpdateTime(now); |
| | | if (!actionService.updateById(action)) { |
| | | log.error("hk state close action failed, orderId={}, actionId={}", orderId, actionId); |
| | | } else { |
| | | log.info("hk state close action success, orderId={}, actionId={}, hkActionId={}", |
| | | orderId, actionId, actionState.getActionId()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private boolean isOrderCompleted(HkState state) { |
| | | if (!Cools.isEmpty(state.getNodeStates()) || !Cools.isEmpty(state.getEdgeStates())) { |
| | | return false; |
| | | } |
| | | |
| | | if (Cools.isEmpty(state.getActionStates())) { |
| | | return true; |
| | | } |
| | | |
| | | for (HkStateActionState actionState : state.getActionStates()) { |
| | | if (actionState == null) { |
| | | continue; |
| | | } |
| | | |
| | | HkActionStatusType status = actionState.getActionStatus(); |
| | | if (status == null |
| | | || status == HkActionStatusType.WAITING |
| | | || status == HkActionStatusType.INITIALIZING |
| | | || status == HkActionStatusType.RUNNING |
| | | || status == HkActionStatusType.PAUSED |
| | | || status == HkActionStatusType.FAILED) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | private void settleCompletedOrder(HkState state) { |
| | | String orderId = state.getOrderId(); |
| | | String completeKey = buildCompleteKey(state); |
| | | if (redis.getObject(HK_ORDER_COMPLETE_FLAG, completeKey) != null) { |
| | | return; |
| | | } |
| | | |
| | | List<Segment> segmentList = segmentService.list(new LambdaQueryWrapper<Segment>() |
| | | .eq(Segment::getGroupId, orderId) |
| | | .orderByAsc(Segment::getSerial)); |
| | | if (Cools.isEmpty(segmentList)) { |
| | | log.warn("hk state order completed but no segment found, agvNo={}, orderId={}, orderUpdateId={}", |
| | | state.getSerialNumber(), orderId, state.getOrderUpdateId()); |
| | | return; |
| | | } |
| | | |
| | | if (!hasReachedOrderTail(state, segmentList)) { |
| | | return; |
| | | } |
| | | |
| | | boolean needSettle = segmentList.stream() |
| | | .anyMatch(segment -> !SegmentStateType.FINISH.toString().equals(segment.getState())); |
| | | if (!needSettle) { |
| | | redis.setObject(HK_ORDER_COMPLETE_FLAG, completeKey, Boolean.TRUE, COMPLETE_MARK_EXPIRE_SECONDS); |
| | | return; |
| | | } |
| | | |
| | | mainService.settleSegmentList(segmentList, orderId); |
| | | redis.setObject(HK_ORDER_COMPLETE_FLAG, completeKey, Boolean.TRUE, COMPLETE_MARK_EXPIRE_SECONDS); |
| | | log.info("hk state settle completed order, agvNo={}, orderId={}, orderUpdateId={}", |
| | | state.getSerialNumber(), orderId, state.getOrderUpdateId()); |
| | | } |
| | | |
| | | private String buildCompleteKey(HkState state) { |
| | | return state.getSerialNumber() |
| | | + "_" |
| | | + state.getOrderId() |
| | | + "_" |
| | | + (state.getOrderUpdateId() == null ? "null" : state.getOrderUpdateId()); |
| | | } |
| | | |
| | | private boolean hasReachedOrderTail(HkState state, List<Segment> segmentList) { |
| | | Long lastNodeSequenceId = state.getLastNodeSequenceId(); |
| | | if (lastNodeSequenceId == null) { |
| | | return false; |
| | | } |
| | | |
| | | long expectedLastNodeSequenceId = segmentList.size() * 2L; |
| | | return lastNodeSequenceId >= expectedLastNodeSequenceId; |
| | | } |
| | | |
| | | private Long parseActionId(String hkActionId) { |
| | | if (Cools.isEmpty(hkActionId) || hkActionId.length() < 2) { |
| | | return null; |
| | | } |
| | | if (hkActionId.charAt(0) != 'A' && hkActionId.charAt(0) != 'a') { |
| | | return null; |
| | | } |
| | | |
| | | try { |
| | | return Long.parseLong(hkActionId.substring(1)); |
| | | } catch (NumberFormatException e) { |
| | | log.warn("parse hk action id failed, hkActionId={}", hkActionId); |
| | | return null; |
| | | } |
| | | } |
| | | } |