fix: 为日计划调度增加排他领取
This commit is contained in:
@@ -62,4 +62,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode DAILY_PLAN_CODE_GENERATE_FAILED = new ErrorCode(37, "日计划编码生成失败");
|
||||
ErrorCode DAILY_PLAN_STRATEGY_VERSION_CONFLICT = new ErrorCode(38, "日计划策略已变化,请重新获取调度候选");
|
||||
ErrorCode DAILY_PLAN_PROGRESS_QTY_NOT_POSITIVE = new ErrorCode(39, "日计划作业进度数量必须为正整数");
|
||||
ErrorCode DAILY_PLAN_CLAIM_CONFLICT = new ErrorCode(40, "日计划已被其他调度器领取,请重新获取候选");
|
||||
ErrorCode DAILY_PLAN_CLAIM_INVALID = new ErrorCode(41, "日计划领取标识无效、已结束或已过期");
|
||||
ErrorCode DAILY_PLAN_CLAIM_MISMATCH = new ErrorCode(42, "日计划领取信息与进度确认不一致");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.code.nl.module.lms.dal.dataobject.dailyplan;
|
||||
|
||||
import cn.code.nl.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** LMS 日计划调度领取 DO。 */
|
||||
@TableName("lms_daily_plan_claim")
|
||||
@Data
|
||||
public class DailyPlanClaimDO extends TenantBaseDO {
|
||||
|
||||
@TableId
|
||||
private Long claimId;
|
||||
private String claimToken;
|
||||
private Long dailyPlanId;
|
||||
private Integer strategyType;
|
||||
private Integer claimedQty;
|
||||
private Integer planVersion;
|
||||
private Integer claimStatus;
|
||||
private Integer activeFlag;
|
||||
private LocalDateTime expireTime;
|
||||
private LocalDateTime confirmedTime;
|
||||
private String operator;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.code.nl.module.lms.dal.mysql.dailyplan;
|
||||
|
||||
import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.code.nl.module.lms.dal.dataobject.dailyplan.DailyPlanClaimDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** LMS 日计划调度领取 Mapper。 */
|
||||
@Mapper
|
||||
public interface DailyPlanClaimMapper extends BaseMapperX<DailyPlanClaimDO> {
|
||||
|
||||
int insertClaim(@Param("claim") DailyPlanClaimDO claim);
|
||||
|
||||
DailyPlanClaimDO selectByToken(@Param("claimToken") String claimToken);
|
||||
|
||||
int confirmClaim(@Param("claimId") Long claimId, @Param("updater") String updater);
|
||||
|
||||
int releaseClaim(@Param("claimToken") String claimToken, @Param("updater") String updater);
|
||||
|
||||
int renewClaim(@Param("claimToken") String claimToken, @Param("expireTime") LocalDateTime expireTime,
|
||||
@Param("updater") String updater);
|
||||
|
||||
int expireClaims(@Param("now") LocalDateTime now, @Param("updater") String updater);
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package cn.code.nl.module.lms.service.dailyplan;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** 供日计划定时调度器使用的候选任务。 */
|
||||
@Data
|
||||
public class DailyPlanScheduleCandidate {
|
||||
@@ -24,4 +26,8 @@ public class DailyPlanScheduleCandidate {
|
||||
private Integer version;
|
||||
/** 本轮使用的策略模式。 */
|
||||
private Integer strategyMode;
|
||||
/** 本次排他领取标识,确认进度时必须原样传回。 */
|
||||
private String claimToken;
|
||||
/** 领取租约过期时间。 */
|
||||
private LocalDateTime claimExpireTime;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,17 @@ public interface DailyPlanScheduleService {
|
||||
DailyPlanScheduleCandidate getNextSleevingCandidate(String operator);
|
||||
|
||||
/** 原子增加已备货数量。 */
|
||||
void increaseStockedQuantity(Long dailyPlanId, Integer quantity, Integer version, String operator);
|
||||
void increaseStockedQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version, String operator);
|
||||
|
||||
/** 原子增加已套管数量。 */
|
||||
void increaseSleevedQuantity(Long dailyPlanId, Integer quantity, Integer version, String operator);
|
||||
void increaseSleevedQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version, String operator);
|
||||
|
||||
/** 延长仍在执行中的领取租约。 */
|
||||
void renewClaim(String claimToken, String operator);
|
||||
|
||||
/** 主动释放未执行的领取,使计划可重新参与调度。 */
|
||||
void releaseClaim(String claimToken, String operator);
|
||||
|
||||
/** 回收超时领取,返回回收数量;供后续定时器调用。 */
|
||||
int releaseExpiredClaims(String operator);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package cn.code.nl.module.lms.service.dailyplan;
|
||||
|
||||
import cn.code.nl.module.lms.dal.dataobject.dailyplan.DailyPlanClaimDO;
|
||||
import cn.code.nl.module.lms.dal.dataobject.dailyplan.DailyPlanDO;
|
||||
import cn.code.nl.module.lms.dal.dataobject.dailyplan.DailyPlanOperationLogDO;
|
||||
import cn.code.nl.module.lms.dal.dataobject.dailyplan.DailyPlanStrategyDO;
|
||||
import cn.code.nl.module.lms.dal.mysql.dailyplan.DailyPlanClaimMapper;
|
||||
import cn.code.nl.module.lms.dal.mysql.dailyplan.DailyPlanMapper;
|
||||
import cn.code.nl.module.lms.dal.mysql.dailyplan.DailyPlanOperationLogMapper;
|
||||
import cn.code.nl.module.lms.dal.mysql.dailyplan.DailyPlanStrategyMapper;
|
||||
@@ -10,15 +12,22 @@ import cn.code.nl.module.lms.enums.DailyPlanOrderStatusEnum;
|
||||
import cn.code.nl.module.lms.enums.DailyPlanStrategyModeEnum;
|
||||
import cn.code.nl.module.lms.enums.DailyPlanStrategyTypeEnum;
|
||||
import cn.code.nl.module.lms.enums.DailyPlanWorkStatusEnum;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_CLAIM_CONFLICT;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_CLAIM_INVALID;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_CLAIM_MISMATCH;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_COMPLETED_QTY_EXCEEDS_TOTAL;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_NOT_EXISTS;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_PROGRESS_QTY_NOT_POSITIVE;
|
||||
@@ -34,23 +43,30 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
private static final String TARGET_STOCKING = "STOCKING";
|
||||
private static final String TARGET_SLEEVING = "SLEEVING";
|
||||
private static final String TYPE_PROGRESS = "PROGRESS";
|
||||
private static final int CLAIM_ACTIVE = 0;
|
||||
|
||||
@Resource
|
||||
private DailyPlanMapper dailyPlanMapper;
|
||||
@Resource
|
||||
private DailyPlanClaimMapper dailyPlanClaimMapper;
|
||||
@Resource
|
||||
private DailyPlanStrategyMapper dailyPlanStrategyMapper;
|
||||
@Resource
|
||||
private DailyPlanOperationLogMapper dailyPlanOperationLogMapper;
|
||||
@Value("${lms.daily-plan.claim-timeout-seconds:300}")
|
||||
private long claimTimeoutSeconds;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DailyPlanScheduleCandidate getNextStockingCandidate(String operator) {
|
||||
expireClaims(operator);
|
||||
return selectCandidate(DailyPlanStrategyTypeEnum.STOCKING, dailyPlanMapper.selectStockingCandidates(), operator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public DailyPlanScheduleCandidate getNextSleevingCandidate(String operator) {
|
||||
expireClaims(operator);
|
||||
return selectCandidate(DailyPlanStrategyTypeEnum.SLEEVING, dailyPlanMapper.selectSleevingCandidates(), operator);
|
||||
}
|
||||
|
||||
@@ -69,20 +85,21 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
}
|
||||
if (mode == DailyPlanStrategyModeEnum.SEQUENCE) {
|
||||
DailyPlanDO selected = candidates.get(0);
|
||||
return convertCandidate(selected, remaining(selected, type), mode.getCode());
|
||||
return claimCandidate(selected, remaining(selected, type), mode.getCode(), type, operator);
|
||||
}
|
||||
|
||||
int selectedIndex = findCursorIndex(candidates, strategy.getCursorDailyPlanId());
|
||||
DailyPlanDO selected = candidates.get(selectedIndex);
|
||||
DailyPlanDO next = candidates.get((selectedIndex + 1) % candidates.size());
|
||||
int affected = dailyPlanStrategyMapper.updateCursorWithVersion(strategy.getStrategyId(),
|
||||
next.getDailyPlanId(), strategy.getVersion(), normalizedOperator(operator));
|
||||
int quantity = Math.min(selected.getWeight(), remaining(selected, type));
|
||||
DailyPlanScheduleCandidate candidate = claimCandidate(selected, quantity, mode.getCode(), type, operator);
|
||||
int affected = dailyPlanStrategyMapper.updateCursorWithVersion(strategy.getStrategyId(), next.getDailyPlanId(),
|
||||
strategy.getVersion(), normalizedOperator(operator));
|
||||
if (affected != 1) {
|
||||
// 本次候选不应在游标推进失败时被执行,调用方可重新获取最新候选。
|
||||
throw exception(DAILY_PLAN_STRATEGY_VERSION_CONFLICT);
|
||||
}
|
||||
int quantity = Math.min(selected.getWeight(), remaining(selected, type));
|
||||
return convertCandidate(selected, quantity, mode.getCode());
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private int findCursorIndex(List<DailyPlanDO> candidates, Long cursorDailyPlanId) {
|
||||
@@ -101,7 +118,25 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
return plan.getPlanQty() + plan.getAppendQty() - completed;
|
||||
}
|
||||
|
||||
private DailyPlanScheduleCandidate convertCandidate(DailyPlanDO plan, int quantity, Integer strategyMode) {
|
||||
private DailyPlanScheduleCandidate claimCandidate(DailyPlanDO plan, int quantity, Integer strategyMode,
|
||||
DailyPlanStrategyTypeEnum type, String operator) {
|
||||
LocalDateTime expireTime = nextClaimExpireTime();
|
||||
DailyPlanClaimDO claim = new DailyPlanClaimDO();
|
||||
claim.setClaimId(IdWorker.getId());
|
||||
claim.setClaimToken(IdUtil.fastSimpleUUID());
|
||||
claim.setDailyPlanId(plan.getDailyPlanId());
|
||||
claim.setStrategyType(type.getCode());
|
||||
claim.setClaimedQty(quantity);
|
||||
claim.setPlanVersion(plan.getVersion());
|
||||
claim.setExpireTime(expireTime);
|
||||
claim.setOperator(normalizedOperator(operator));
|
||||
try {
|
||||
if (dailyPlanClaimMapper.insertClaim(claim) != 1) {
|
||||
throw exception(DAILY_PLAN_CLAIM_CONFLICT);
|
||||
}
|
||||
} catch (DuplicateKeyException ex) {
|
||||
throw exception(DAILY_PLAN_CLAIM_CONFLICT);
|
||||
}
|
||||
DailyPlanScheduleCandidate candidate = new DailyPlanScheduleCandidate();
|
||||
candidate.setDailyPlanId(plan.getDailyPlanId());
|
||||
candidate.setPlanCode(plan.getPlanCode());
|
||||
@@ -112,33 +147,39 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
candidate.setSuggestedQuantity(quantity);
|
||||
candidate.setVersion(plan.getVersion());
|
||||
candidate.setStrategyMode(strategyMode);
|
||||
candidate.setClaimToken(claim.getClaimToken());
|
||||
candidate.setClaimExpireTime(expireTime);
|
||||
return candidate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void increaseStockedQuantity(Long dailyPlanId, Integer quantity, Integer version, String operator) {
|
||||
increaseQuantity(dailyPlanId, quantity, version, operator, DailyPlanStrategyTypeEnum.STOCKING);
|
||||
public void increaseStockedQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version,
|
||||
String operator) {
|
||||
increaseQuantity(claimToken, dailyPlanId, quantity, version, operator, DailyPlanStrategyTypeEnum.STOCKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void increaseSleevedQuantity(Long dailyPlanId, Integer quantity, Integer version, String operator) {
|
||||
increaseQuantity(dailyPlanId, quantity, version, operator, DailyPlanStrategyTypeEnum.SLEEVING);
|
||||
public void increaseSleevedQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version,
|
||||
String operator) {
|
||||
increaseQuantity(claimToken, dailyPlanId, quantity, version, operator, DailyPlanStrategyTypeEnum.SLEEVING);
|
||||
}
|
||||
|
||||
private void increaseQuantity(Long dailyPlanId, Integer quantity, Integer version, String operator,
|
||||
private void increaseQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version, String operator,
|
||||
DailyPlanStrategyTypeEnum type) {
|
||||
if (quantity == null || quantity <= 0) {
|
||||
throw exception(DAILY_PLAN_PROGRESS_QTY_NOT_POSITIVE);
|
||||
}
|
||||
DailyPlanClaimDO claim = validateActiveClaim(claimToken);
|
||||
if (!claim.getDailyPlanId().equals(dailyPlanId) || !claim.getStrategyType().equals(type.getCode())
|
||||
|| !claim.getClaimedQty().equals(quantity) || !claim.getPlanVersion().equals(version)) {
|
||||
throw exception(DAILY_PLAN_CLAIM_MISMATCH);
|
||||
}
|
||||
DailyPlanDO plan = dailyPlanMapper.selectDailyPlanById(dailyPlanId);
|
||||
if (plan == null) {
|
||||
throw exception(DAILY_PLAN_NOT_EXISTS);
|
||||
}
|
||||
if (!plan.getVersion().equals(version)) {
|
||||
throw exception(DAILY_PLAN_VERSION_CONFLICT);
|
||||
}
|
||||
Integer workStatus = type == DailyPlanStrategyTypeEnum.STOCKING
|
||||
? plan.getStockingStatus() : plan.getSleevingStatus();
|
||||
if (!DailyPlanOrderStatusEnum.IN_PROGRESS.getCode().equals(plan.getOrderStatus())
|
||||
@@ -152,14 +193,61 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
throw exception(DAILY_PLAN_COMPLETED_QTY_EXCEEDS_TOTAL);
|
||||
}
|
||||
int affected = type == DailyPlanStrategyTypeEnum.STOCKING
|
||||
? dailyPlanMapper.increaseStockedQuantity(dailyPlanId, quantity, version, normalizedOperator(operator))
|
||||
: dailyPlanMapper.increaseSleevedQuantity(dailyPlanId, quantity, version, normalizedOperator(operator));
|
||||
? dailyPlanMapper.increaseStockedQuantity(dailyPlanId, quantity, plan.getVersion(), normalizedOperator(operator))
|
||||
: dailyPlanMapper.increaseSleevedQuantity(dailyPlanId, quantity, plan.getVersion(), normalizedOperator(operator));
|
||||
if (affected != 1) {
|
||||
throw exception(DAILY_PLAN_VERSION_CONFLICT);
|
||||
}
|
||||
if (dailyPlanClaimMapper.confirmClaim(claim.getClaimId(), normalizedOperator(operator)) != 1) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
insertProgressLog(dailyPlanId, type, before, before + quantity, quantity, operator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void renewClaim(String claimToken, String operator) {
|
||||
validateActiveClaim(claimToken);
|
||||
LocalDateTime expireTime = nextClaimExpireTime();
|
||||
if (dailyPlanClaimMapper.renewClaim(claimToken, expireTime, normalizedOperator(operator)) != 1) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void releaseClaim(String claimToken, String operator) {
|
||||
if (dailyPlanClaimMapper.releaseClaim(claimToken, normalizedOperator(operator)) != 1) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int releaseExpiredClaims(String operator) {
|
||||
return expireClaims(operator);
|
||||
}
|
||||
|
||||
private int expireClaims(String operator) {
|
||||
return dailyPlanClaimMapper.expireClaims(LocalDateTime.now(), normalizedOperator(operator));
|
||||
}
|
||||
|
||||
private DailyPlanClaimDO validateActiveClaim(String claimToken) {
|
||||
if (StrUtil.isBlank(claimToken)) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
DailyPlanClaimDO claim = dailyPlanClaimMapper.selectByToken(claimToken);
|
||||
if (claim == null || !Integer.valueOf(CLAIM_ACTIVE).equals(claim.getClaimStatus())
|
||||
|| claim.getActiveFlag() == null || !claim.getExpireTime().isAfter(LocalDateTime.now())) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
return claim;
|
||||
}
|
||||
|
||||
private LocalDateTime nextClaimExpireTime() {
|
||||
return LocalDateTime.now().plusSeconds(Math.max(1L, claimTimeoutSeconds));
|
||||
}
|
||||
|
||||
private void insertProgressLog(Long dailyPlanId, DailyPlanStrategyTypeEnum type, int before, int after,
|
||||
int quantity, String operator) {
|
||||
DailyPlanOperationLogDO log = new DailyPlanOperationLogDO();
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.code.nl.module.lms.dal.mysql.dailyplan.DailyPlanClaimMapper">
|
||||
|
||||
<sql id="claimColumns">
|
||||
claim_id, claim_token, daily_plan_id, strategy_type, claimed_qty, plan_version,
|
||||
claim_status, active_flag, expire_time, confirmed_time, operator,
|
||||
creator, create_time, updater, update_time, deleted, tenant_id
|
||||
</sql>
|
||||
|
||||
<insert id="insertClaim">
|
||||
INSERT INTO lms_daily_plan_claim
|
||||
(claim_id, claim_token, daily_plan_id, strategy_type, claimed_qty, plan_version,
|
||||
claim_status, active_flag, expire_time, operator, creator, updater)
|
||||
VALUES
|
||||
(#{claim.claimId}, #{claim.claimToken}, #{claim.dailyPlanId}, #{claim.strategyType},
|
||||
#{claim.claimedQty}, #{claim.planVersion}, 0, 1, #{claim.expireTime},
|
||||
#{claim.operator}, #{claim.operator}, #{claim.operator})
|
||||
</insert>
|
||||
|
||||
<select id="selectByToken" resultType="cn.code.nl.module.lms.dal.dataobject.dailyplan.DailyPlanClaimDO">
|
||||
SELECT <include refid="claimColumns"/>
|
||||
FROM lms_daily_plan_claim
|
||||
WHERE claim_token = #{claimToken} AND deleted = b'0'
|
||||
</select>
|
||||
|
||||
<update id="confirmClaim">
|
||||
UPDATE lms_daily_plan_claim
|
||||
SET claim_status = 1, active_flag = NULL, confirmed_time = NOW(), updater = #{updater}
|
||||
WHERE claim_id = #{claimId} AND claim_status = 0 AND active_flag = 1
|
||||
AND expire_time > NOW() AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
<update id="releaseClaim">
|
||||
UPDATE lms_daily_plan_claim
|
||||
SET claim_status = 2, active_flag = NULL, updater = #{updater}
|
||||
WHERE claim_token = #{claimToken} AND claim_status = 0 AND active_flag = 1 AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
<update id="renewClaim">
|
||||
UPDATE lms_daily_plan_claim
|
||||
SET expire_time = #{expireTime}, updater = #{updater}
|
||||
WHERE claim_token = #{claimToken} AND claim_status = 0 AND active_flag = 1
|
||||
AND expire_time > NOW() AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
<update id="expireClaims">
|
||||
UPDATE lms_daily_plan_claim
|
||||
SET claim_status = 3, active_flag = NULL, updater = #{updater}
|
||||
WHERE claim_status = 0 AND active_flag = 1 AND expire_time <= #{now} AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -93,6 +93,13 @@
|
||||
AND stocking_status = 1
|
||||
AND stocked_qty < plan_qty + append_qty
|
||||
AND deleted = b'0'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM lms_daily_plan_claim claim
|
||||
WHERE claim.daily_plan_id = lms_daily_plan.daily_plan_id
|
||||
AND claim.tenant_id = lms_daily_plan.tenant_id
|
||||
AND claim.strategy_type = 1 AND claim.claim_status = 0
|
||||
AND claim.active_flag = 1 AND claim.expire_time > NOW() AND claim.deleted = b'0'
|
||||
)
|
||||
ORDER BY sort_seq ASC, daily_plan_id ASC
|
||||
</select>
|
||||
|
||||
@@ -104,6 +111,13 @@
|
||||
AND sleeving_status = 1
|
||||
AND sleeved_qty < plan_qty + append_qty
|
||||
AND deleted = b'0'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM lms_daily_plan_claim claim
|
||||
WHERE claim.daily_plan_id = lms_daily_plan.daily_plan_id
|
||||
AND claim.tenant_id = lms_daily_plan.tenant_id
|
||||
AND claim.strategy_type = 2 AND claim.claim_status = 0
|
||||
AND claim.active_flag = 1 AND claim.expire_time > NOW() AND claim.deleted = b'0'
|
||||
)
|
||||
ORDER BY sort_seq ASC, daily_plan_id ASC
|
||||
</select>
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ CREATE TABLE IF NOT EXISTS `lms_daily_plan` (
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`daily_plan_id`),
|
||||
UNIQUE KEY `uk_plan_code_tenant` (`plan_code`, `tenant_id`),
|
||||
UNIQUE KEY `uk_erp_order_code_tenant` (`erp_order_code`, `tenant_id`)
|
||||
UNIQUE KEY `uk_erp_order_code_tenant` (`erp_order_code`, `tenant_id`),
|
||||
KEY `idx_stocking_candidate` (`tenant_id`, `deleted`, `order_status`, `stocking_status`, `sort_seq`, `daily_plan_id`),
|
||||
KEY `idx_sleeving_candidate` (`tenant_id`, `deleted`, `order_status`, `sleeving_status`, `sort_seq`, `daily_plan_id`)
|
||||
) COMMENT='LMS日计划';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lms_daily_plan_strategy` (
|
||||
@@ -57,6 +59,30 @@ CREATE TABLE IF NOT EXISTS `lms_daily_plan_strategy` (
|
||||
UNIQUE KEY `uk_strategy_type_tenant` (`strategy_type`, `tenant_id`)
|
||||
) COMMENT='LMS日计划调度策略';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lms_daily_plan_claim` (
|
||||
`claim_id` bigint NOT NULL COMMENT '领取ID',
|
||||
`claim_token` varchar(64) NOT NULL COMMENT '对外领取标识',
|
||||
`daily_plan_id` bigint NOT NULL COMMENT '日计划ID',
|
||||
`strategy_type` tinyint NOT NULL COMMENT '作业类型:1备货,2套管',
|
||||
`claimed_qty` int NOT NULL COMMENT '本次预占数量',
|
||||
`plan_version` int NOT NULL COMMENT '领取时日计划版本号',
|
||||
`claim_status` tinyint NOT NULL DEFAULT 0 COMMENT '领取状态:0执行中,1已确认,2已释放,3已过期',
|
||||
`active_flag` tinyint DEFAULT 1 COMMENT '有效领取唯一标记,终态置空',
|
||||
`expire_time` datetime NOT NULL COMMENT '租约过期时间',
|
||||
`confirmed_time` datetime DEFAULT NULL COMMENT '确认时间',
|
||||
`operator` varchar(64) NOT NULL COMMENT '领取人/执行器',
|
||||
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`claim_id`),
|
||||
UNIQUE KEY `uk_claim_token_tenant` (`claim_token`, `tenant_id`),
|
||||
UNIQUE KEY `uk_active_plan_type_tenant` (`daily_plan_id`, `strategy_type`, `active_flag`, `tenant_id`),
|
||||
KEY `idx_claim_expire` (`tenant_id`, `claim_status`, `expire_time`)
|
||||
) COMMENT='LMS日计划调度领取';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lms_daily_plan_operation_log` (
|
||||
`operation_log_id` bigint NOT NULL COMMENT '操作日志ID',
|
||||
`daily_plan_id` bigint DEFAULT NULL COMMENT '日计划ID',
|
||||
@@ -73,6 +99,24 @@ CREATE TABLE IF NOT EXISTS `lms_daily_plan_operation_log` (
|
||||
PRIMARY KEY (`operation_log_id`)
|
||||
) COMMENT='LMS日计划操作日志';
|
||||
|
||||
-- 兼容已执行过旧版脚本的数据库,幂等补充候选组合索引。
|
||||
SET @lms_daily_plan_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'lms_daily_plan' AND index_name = 'idx_stocking_candidate'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE lms_daily_plan ADD INDEX idx_stocking_candidate (tenant_id, deleted, order_status, stocking_status, sort_seq, daily_plan_id)');
|
||||
PREPARE lms_daily_plan_stmt FROM @lms_daily_plan_ddl;
|
||||
EXECUTE lms_daily_plan_stmt;
|
||||
DEALLOCATE PREPARE lms_daily_plan_stmt;
|
||||
SET @lms_daily_plan_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'lms_daily_plan' AND index_name = 'idx_sleeving_candidate'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE lms_daily_plan ADD INDEX idx_sleeving_candidate (tenant_id, deleted, order_status, sleeving_status, sort_seq, daily_plan_id)');
|
||||
PREPARE lms_daily_plan_stmt FROM @lms_daily_plan_ddl;
|
||||
EXECUTE lms_daily_plan_stmt;
|
||||
DEALLOCATE PREPARE lms_daily_plan_stmt;
|
||||
|
||||
-- 2093号段用于 LMS 日计划固定基础数据;编码格式:DP + yyyyMMdd + 4位日流水。
|
||||
INSERT INTO base_code_rule
|
||||
(id, rule_name, rule_code, segment_config, code_separator, letter_case, total_length,
|
||||
|
||||
Reference in New Issue
Block a user