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;
|
}
|
}
|
}
|