package com.zy.acs.manager.manager.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.zy.acs.framework.common.Cools; import com.zy.acs.manager.common.exception.BusinessException; import com.zy.acs.manager.manager.entity.Sta; import com.zy.acs.manager.manager.entity.StaReserve; import com.zy.acs.manager.manager.entity.Task; import com.zy.acs.manager.manager.enums.StaReserveStateType; import com.zy.acs.manager.manager.enums.StaReserveType; import com.zy.acs.manager.manager.enums.StatusType; import com.zy.acs.manager.manager.mapper.StaMapper; import com.zy.acs.manager.manager.mapper.StaReserveMapper; import com.zy.acs.manager.manager.service.StaReserveService; import com.zy.acs.manager.manager.service.StaService; 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; import java.util.Objects; import java.util.Optional; @Service("staReserveService") public class StaReserveServiceImpl extends ServiceImpl implements StaReserveService { public static final Long RESERVE_EXPIRE_TIME = 30 * 60 * 1000L; public static final Long WAITING_EXPIRE_TIME = 5 * 60 * 1000L; public static final Integer DEFAULT_QTY = 1; @Autowired private StaService staService; @Autowired private StaMapper staMapper; @Override @Transactional(rollbackFor = Exception.class) public StaReserve reserveStaIn(Sta sta, Task task, Integer qty) { qty = Optional.ofNullable(qty).orElse(DEFAULT_QTY); // reserve sta in if (staMapper.tryReserveIn(sta.getId(), qty) < qty) { throw new BusinessException("Sta[" + sta.getStaNo() + "] can't reserve IN"); } Date now = new Date(); // save staReserve StaReserve reserve = new StaReserve(); reserve.setStaId(sta.getId()); reserve.setTaskId(task.getId()); reserve.setType(StaReserveType.IN.toString()); reserve.setQty(qty); reserve.setState(StaReserveStateType.RESERVED.toString()); reserve.setUniqKey(this.generateReserveUniqKey(sta.getId(), task.getId(), StaReserveType.IN)); reserve.setExpireTime(new Date(now.getTime() + RESERVE_EXPIRE_TIME)); reserve.setStatus(StatusType.ENABLE.val); reserve.setCreateTime(now); reserve.setUpdateTime(now); if (!this.save(reserve)) { staMapper.releaseReserveIn(sta.getId(), qty); throw new BusinessException("reserve record insert failed"); } return reserve; } @Override @Transactional(rollbackFor = Exception.class) public StaReserve reserveStaOut(Sta sta, Task task, Integer qty) { qty = Optional.ofNullable(qty).orElse(DEFAULT_QTY); // reserve sta out if (staMapper.tryReserveOut(sta.getId(), qty) < qty) { throw new BusinessException("Sta[" + sta.getStaNo() + "] can't reserve OUT"); } Date now = new Date(); // save staReserve StaReserve reserve = new StaReserve(); reserve.setStaId(sta.getId()); reserve.setTaskId(task.getId()); reserve.setType(StaReserveType.OUT.toString()); reserve.setQty(qty); reserve.setState(StaReserveStateType.RESERVED.toString()); reserve.setUniqKey(this.generateReserveUniqKey(sta.getId(), task.getId(), StaReserveType.OUT)); reserve.setExpireTime(new Date(now.getTime() + RESERVE_EXPIRE_TIME)); reserve.setStatus(StatusType.ENABLE.val); reserve.setCreateTime(now); reserve.setUpdateTime(now); if (!this.save(reserve)) { staMapper.releaseReserveOut(sta.getId(), qty); throw new BusinessException("reserve record insert failed"); } return reserve; } @Override @Transactional(rollbackFor = Exception.class) public Boolean waitingStaReserve(Sta sta, Task task, Integer qty, StaReserveType type) { qty = Optional.ofNullable(qty).orElse(DEFAULT_QTY); // update reserve to be waiting state int changed = this.baseMapper.updateStateToWaiting(task.getId() , sta.getId() , type.toString() , StaReserveStateType.WAITING.toString() , WAITING_EXPIRE_TIME ); if (changed > 0) { return true; } List list = this.list(new LambdaQueryWrapper() .eq(StaReserve::getStaId, sta.getId()) .eq(StaReserve::getTaskId, task.getId()) .eq(StaReserve::getType, type.toString()) .eq(StaReserve::getStatus, StatusType.ENABLE.val) ); if (Cools.isEmpty(list)) { return false; } StaReserve reserve = list.get(0); StaReserveStateType stateType = StaReserveStateType.of(reserve.getState()); switch (Objects.requireNonNull(stateType)) { case WAITING: case CONFIRMED: return true; default: return false; } } @Override public Boolean rollbackWaitingToReserved(Sta sta, Task task, StaReserveType type) { int changed = this.baseMapper.updateStateBackToWaiting( task.getId() , sta.getId() , type.toString() , StaReserveStateType.RESERVED.toString() , WAITING_EXPIRE_TIME ); return changed > 0; } @Override @Transactional(rollbackFor = Exception.class) public void confirmStaReserve(Sta sta, Task task, Integer qty, StaReserveType type) { qty = Optional.ofNullable(qty).orElse(DEFAULT_QTY); // update reserve state to be confirmed if (0 == this.baseMapper.updateState(task.getId(), sta.getId(), type.toString(), StaReserveStateType.CONFIRMED.toString())) { log.error("failed to confirm sta reserve"); return; } int cntOfDealWithReserve = 0; switch (type) { case IN: cntOfDealWithReserve = staMapper.confirmReserveIn(sta.getId(), qty); break; case OUT: cntOfDealWithReserve = staMapper.confirmReserveOut(sta.getId(), qty); break; default: break; } if (cntOfDealWithReserve == 0) { throw new BusinessException("Sta[" + sta.getStaNo() + "] confirm failed, type=" + type.toString()); } } @Override public void cancelStaReserve(Sta sta, Task task, Integer qty, StaReserveType type) { qty = Optional.ofNullable(qty).orElse(DEFAULT_QTY); // update reserve state to be canceled if (0 == this.baseMapper.updateState(task.getId(), sta.getId(), type.toString(), StaReserveStateType.CANCELLED.toString())) { log.error("failed to cancel sta reserve"); return; } int cntOfDealWithReserve = 0; switch (type) { case IN: cntOfDealWithReserve = staMapper.releaseReserveIn(sta.getId(), qty); break; case OUT: cntOfDealWithReserve = staMapper.releaseReserveOut(sta.getId(), qty); break; default: break; } if (cntOfDealWithReserve == 0) { throw new BusinessException("Sta[" + sta.getStaNo() + "] cancel failed, type=" + type.toString()); } } private String generateReserveUniqKey(Long staId, Long taskId, StaReserveType type) { return "STA:" + staId + "-TASK:" + taskId + "-T:" + type.toString(); } }