fix: 使用领取令牌隔离日计划进度
This commit is contained in:
@@ -225,25 +225,23 @@ List<DailyPlanDO> selectSleevingCandidates();
|
||||
|
||||
- [ ] **步骤 2:实现受控写入**
|
||||
|
||||
XML 提供 `insertDailyPlan`、`updateNotStartedPlan`、`updateStateWithVersion`、`updateSortWithVersion`、`updateWeightWithVersion` 和两个原子进度方法。版本更新必须使用:
|
||||
XML 提供 `insertDailyPlan`、`updateNotStartedPlan`、`updateStateWithVersion`、`updateSortWithVersion`、`updateWeightWithVersion` 和两个基于 Claim 的原子进度方法。页面写操作使用日计划版本;调度进度以 Claim 令牌及领取时对应作业进度作为并发边界:
|
||||
|
||||
```sql
|
||||
UPDATE lms_daily_plan
|
||||
SET stocked_qty = stocked_qty + #{incrementQty},
|
||||
stocking_status = CASE
|
||||
WHEN stocked_qty + #{incrementQty} = plan_qty + append_qty THEN 2
|
||||
WHEN stocking_status = 1 AND stocked_qty + #{incrementQty} = plan_qty + append_qty THEN 2
|
||||
ELSE stocking_status
|
||||
END,
|
||||
version = version + 1,
|
||||
updater = #{updater}
|
||||
WHERE daily_plan_id = #{dailyPlanId}
|
||||
AND version = #{version}
|
||||
AND order_status = 1
|
||||
AND stocking_status = 1
|
||||
AND stocked_qty = #{claimProgressQty}
|
||||
AND stocked_qty + #{incrementQty} <= plan_qty + append_qty
|
||||
```
|
||||
|
||||
套管方法使用同样约束。受影响行数不是 1 时由 Service 区分版本冲突或数量超限。
|
||||
套管方法使用独立的 `sleeved_qty` 快照约束。排序、权重、ERP 追加和另一作业进度引起的日计划版本变化不影响确认。取消或结束只阻止新领取,已有有效 Claim 仍允许累计数量,且 SQL 不覆盖用户选择的取消或结束状态。受影响行数不是 1 时由 Service 区分进度冲突或数量超限。
|
||||
|
||||
- [ ] **步骤 3:实现策略与日志 Mapper**
|
||||
|
||||
@@ -359,7 +357,7 @@ POST /lms/daily-plan/erpPush
|
||||
|
||||
- [ ] **步骤 1:定义调度返回对象**
|
||||
|
||||
创建 `DailyPlanScheduleCandidate`,包含日计划 ID、计划编号、物料信息、建议处理数量、版本号和策略模式。
|
||||
创建 `DailyPlanScheduleCandidate`,包含日计划 ID、计划编号、物料信息、建议处理数量、版本号、策略模式、排他 Claim 令牌和租约过期时间。版本号仅供展示审计,不作为进度确认并发边界。
|
||||
|
||||
- [ ] **步骤 2:实现顺序模式选择**
|
||||
|
||||
@@ -367,18 +365,18 @@ POST /lms/daily-plan/erpPush
|
||||
|
||||
- [ ] **步骤 3:实现权重轮转选择**
|
||||
|
||||
根据策略游标从有序候选列表定位下一张;建议数量为 `min(weight, remainingQty)`。完成选择后以版本号更新游标到下一张计划。游标无效时从顺序第一张开始。
|
||||
根据策略游标从有序候选列表定位下一张;建议数量为 `min(weight, remainingQty)`。先原子创建 Claim,成功后再以策略版本号更新游标到下一张计划,两者同事务提交。游标无效时从顺序第一张开始。
|
||||
|
||||
- [ ] **步骤 4:实现原子进度更新**
|
||||
|
||||
提供:
|
||||
|
||||
```java
|
||||
void increaseStockedQuantity(Long dailyPlanId, Integer quantity, Integer version, String operator);
|
||||
void increaseSleevedQuantity(Long dailyPlanId, Integer quantity, Integer version, String operator);
|
||||
void increaseStockedQuantity(String claimToken, Long dailyPlanId, Integer quantity, String operator);
|
||||
void increaseSleevedQuantity(String claimToken, Long dailyPlanId, Integer quantity, String operator);
|
||||
```
|
||||
|
||||
更新到需求总量时同步写完成状态和完成时间,并追加操作日志。版本冲突或数量超限抛明确业务异常。
|
||||
确认先锁定并原子消费 Claim,再按 Claim 保存的对应作业进度快照更新数量并追加日志。备货、套管可独立并发;同一 Claim 重复确认幂等成功。更新到需求总量时,仅当该作业仍在进行中才同步写完成状态和完成时间;若用户已取消或结束则保留终态。另提供 Claim 续租、主动释放和过期回收能力。
|
||||
|
||||
- [ ] **步骤 5:编译并提交调度能力**
|
||||
|
||||
|
||||
@@ -221,11 +221,14 @@ ERP 推送不允许直接修改顺序、权重、当前完成数量或作业状
|
||||
|
||||
## 并发与事务
|
||||
|
||||
- 页面操作和定时器数量更新使用版本号进行乐观锁校验。
|
||||
- 页面状态及资料操作使用日计划版本号进行乐观锁校验;调度数量确认不绑定整张日计划版本。
|
||||
- 状态变更、数量变更和对应操作记录在同一事务中提交。
|
||||
- 批量调整顺序在一个事务内完成;任一计划版本冲突时整体回滚。
|
||||
- 策略切换和轮转游标更新使用版本号,避免两个调度线程重复选择同一轮计划。
|
||||
- 并发失败统一提示“日计划已发生变化,请刷新后重试”。
|
||||
- 每次调度先持久化排他 Claim,Claim 令牌、作业类型、预占数量、领取时作业进度和 Claim 自身版本共同构成确认并发边界。备货与套管 Claim 相互独立。
|
||||
- 进度确认先原子消费 Claim,再以领取时对应作业进度为条件累计数量;重复确认同一已完成 Claim 幂等成功,不重复计数。
|
||||
- 排序、权重、ERP 追加和另一作业进度不会阻断有效 Claim 确认。取消、结束后不再产生新 Claim,但已下发的有效 Claim 仍可确认;确认只累计数量,保留用户选择的取消或结束状态。
|
||||
- Claim 支持续租、主动释放和过期回收;过期或已释放 Claim 不得确认。
|
||||
|
||||
## 错误处理
|
||||
|
||||
|
||||
@@ -65,4 +65,5 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode DAILY_PLAN_CLAIM_CONFLICT = new ErrorCode(40, "日计划已被其他调度器领取,请重新获取候选");
|
||||
ErrorCode DAILY_PLAN_CLAIM_INVALID = new ErrorCode(41, "日计划领取标识无效、已结束或已过期");
|
||||
ErrorCode DAILY_PLAN_CLAIM_MISMATCH = new ErrorCode(42, "日计划领取信息与进度确认不一致");
|
||||
ErrorCode DAILY_PLAN_CLAIM_PROGRESS_CONFLICT = new ErrorCode(43, "日计划作业进度已变化,该领取无法确认");
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ public class DailyPlanClaimDO extends TenantBaseDO {
|
||||
private Integer strategyType;
|
||||
private Integer claimedQty;
|
||||
private Integer planVersion;
|
||||
private Integer progressQty;
|
||||
private Integer version;
|
||||
private Integer claimStatus;
|
||||
private Integer activeFlag;
|
||||
private LocalDateTime expireTime;
|
||||
|
||||
@@ -15,11 +15,15 @@ public interface DailyPlanClaimMapper extends BaseMapperX<DailyPlanClaimDO> {
|
||||
|
||||
DailyPlanClaimDO selectByToken(@Param("claimToken") String claimToken);
|
||||
|
||||
int confirmClaim(@Param("claimId") Long claimId, @Param("updater") String updater);
|
||||
DailyPlanClaimDO selectByTokenForUpdate(@Param("claimToken") String claimToken);
|
||||
|
||||
int confirmClaim(@Param("claimId") Long claimId, @Param("version") Integer version,
|
||||
@Param("updater") String updater);
|
||||
|
||||
int releaseClaim(@Param("claimToken") String claimToken, @Param("updater") String updater);
|
||||
|
||||
int renewClaim(@Param("claimToken") String claimToken, @Param("expireTime") LocalDateTime expireTime,
|
||||
int renewClaim(@Param("claimToken") String claimToken, @Param("version") Integer version,
|
||||
@Param("expireTime") LocalDateTime expireTime,
|
||||
@Param("updater") String updater);
|
||||
|
||||
int expireClaims(@Param("now") LocalDateTime now, @Param("updater") String updater);
|
||||
|
||||
@@ -128,16 +128,16 @@ public interface DailyPlanMapper extends BaseMapperX<DailyPlanDO> {
|
||||
/**
|
||||
* 原子增加已备货数量,并在达到总量时完成备货。
|
||||
*/
|
||||
int increaseStockedQuantity(@Param("dailyPlanId") Long dailyPlanId,
|
||||
int increaseStockedQuantityByClaim(@Param("dailyPlanId") Long dailyPlanId,
|
||||
@Param("incrementQty") Integer incrementQty,
|
||||
@Param("version") Integer version,
|
||||
@Param("expectedQty") Integer expectedQty,
|
||||
@Param("updater") String updater);
|
||||
|
||||
/**
|
||||
* 原子增加已套管数量,并在达到总量时完成套管。
|
||||
*/
|
||||
int increaseSleevedQuantity(@Param("dailyPlanId") Long dailyPlanId,
|
||||
int increaseSleevedQuantityByClaim(@Param("dailyPlanId") Long dailyPlanId,
|
||||
@Param("incrementQty") Integer incrementQty,
|
||||
@Param("version") Integer version,
|
||||
@Param("expectedQty") Integer expectedQty,
|
||||
@Param("updater") String updater);
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ public interface DailyPlanScheduleService {
|
||||
DailyPlanScheduleCandidate getNextSleevingCandidate(String operator);
|
||||
|
||||
/** 原子增加已备货数量。 */
|
||||
void increaseStockedQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version, String operator);
|
||||
void increaseStockedQuantity(String claimToken, Long dailyPlanId, Integer quantity, String operator);
|
||||
|
||||
/** 原子增加已套管数量。 */
|
||||
void increaseSleevedQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version, String operator);
|
||||
void increaseSleevedQuantity(String claimToken, Long dailyPlanId, Integer quantity, String operator);
|
||||
|
||||
/** 延长仍在执行中的领取租约。 */
|
||||
void renewClaim(String claimToken, String operator);
|
||||
|
||||
@@ -8,10 +8,8 @@ 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;
|
||||
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;
|
||||
@@ -28,10 +26,10 @@ import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.ex
|
||||
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_CLAIM_PROGRESS_CONFLICT;
|
||||
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;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_STATUS_OPERATION_NOT_ALLOWED;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_STRATEGY_NOT_EXISTS;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_STRATEGY_VERSION_CONFLICT;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_VERSION_CONFLICT;
|
||||
@@ -44,6 +42,7 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
private static final String TARGET_SLEEVING = "SLEEVING";
|
||||
private static final String TYPE_PROGRESS = "PROGRESS";
|
||||
private static final int CLAIM_ACTIVE = 0;
|
||||
private static final int CLAIM_CONFIRMED = 1;
|
||||
|
||||
@Resource
|
||||
private DailyPlanMapper dailyPlanMapper;
|
||||
@@ -128,6 +127,7 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
claim.setStrategyType(type.getCode());
|
||||
claim.setClaimedQty(quantity);
|
||||
claim.setPlanVersion(plan.getVersion());
|
||||
claim.setProgressQty(type == DailyPlanStrategyTypeEnum.STOCKING ? plan.getStockedQty() : plan.getSleevedQty());
|
||||
claim.setExpireTime(expireTime);
|
||||
claim.setOperator(normalizedOperator(operator));
|
||||
try {
|
||||
@@ -154,56 +154,53 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void increaseStockedQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version,
|
||||
String operator) {
|
||||
increaseQuantity(claimToken, dailyPlanId, quantity, version, operator, DailyPlanStrategyTypeEnum.STOCKING);
|
||||
public void increaseStockedQuantity(String claimToken, Long dailyPlanId, Integer quantity, String operator) {
|
||||
increaseQuantity(claimToken, dailyPlanId, quantity, operator, DailyPlanStrategyTypeEnum.STOCKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void increaseSleevedQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version,
|
||||
String operator) {
|
||||
increaseQuantity(claimToken, dailyPlanId, quantity, version, operator, DailyPlanStrategyTypeEnum.SLEEVING);
|
||||
public void increaseSleevedQuantity(String claimToken, Long dailyPlanId, Integer quantity, String operator) {
|
||||
increaseQuantity(claimToken, dailyPlanId, quantity, operator, DailyPlanStrategyTypeEnum.SLEEVING);
|
||||
}
|
||||
|
||||
private void increaseQuantity(String claimToken, Long dailyPlanId, Integer quantity, Integer version, String operator,
|
||||
private void increaseQuantity(String claimToken, Long dailyPlanId, Integer quantity, String operator,
|
||||
DailyPlanStrategyTypeEnum type) {
|
||||
if (quantity == null || quantity <= 0) {
|
||||
throw exception(DAILY_PLAN_PROGRESS_QTY_NOT_POSITIVE);
|
||||
}
|
||||
DailyPlanClaimDO claim = validateActiveClaim(claimToken);
|
||||
DailyPlanClaimDO claim = getClaimForUpdate(claimToken);
|
||||
if (!claim.getDailyPlanId().equals(dailyPlanId) || !claim.getStrategyType().equals(type.getCode())
|
||||
|| !claim.getClaimedQty().equals(quantity) || !claim.getPlanVersion().equals(version)) {
|
||||
|| !claim.getClaimedQty().equals(quantity)) {
|
||||
throw exception(DAILY_PLAN_CLAIM_MISMATCH);
|
||||
}
|
||||
if (Integer.valueOf(CLAIM_CONFIRMED).equals(claim.getClaimStatus())) {
|
||||
return; // 同一 claim 的重复确认幂等成功,绝不重复累计。
|
||||
}
|
||||
validateActiveClaim(claim);
|
||||
if (dailyPlanClaimMapper.confirmClaim(claim.getClaimId(), claim.getVersion(), normalizedOperator(operator)) != 1) {
|
||||
DailyPlanClaimDO latest = getClaim(claimToken);
|
||||
if (Integer.valueOf(CLAIM_CONFIRMED).equals(latest.getClaimStatus())) {
|
||||
return;
|
||||
}
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
DailyPlanDO plan = dailyPlanMapper.selectDailyPlanById(dailyPlanId);
|
||||
if (plan == null) {
|
||||
throw exception(DAILY_PLAN_NOT_EXISTS);
|
||||
}
|
||||
if (!plan.getVersion().equals(claim.getPlanVersion())) {
|
||||
// 领取后的任何计划变更都会使旧领取失效;不确认 claim,调用方可处理冲突后主动释放或续租。
|
||||
throw exception(DAILY_PLAN_VERSION_CONFLICT);
|
||||
}
|
||||
Integer workStatus = type == DailyPlanStrategyTypeEnum.STOCKING
|
||||
? plan.getStockingStatus() : plan.getSleevingStatus();
|
||||
if (!DailyPlanOrderStatusEnum.IN_PROGRESS.getCode().equals(plan.getOrderStatus())
|
||||
|| !DailyPlanWorkStatusEnum.IN_PROGRESS.getCode().equals(workStatus)) {
|
||||
throw exception(DAILY_PLAN_STATUS_OPERATION_NOT_ALLOWED,
|
||||
plan.getOrderStatus() + "/" + workStatus, "更新作业进度");
|
||||
}
|
||||
int before = type == DailyPlanStrategyTypeEnum.STOCKING ? plan.getStockedQty() : plan.getSleevedQty();
|
||||
long total = (long) plan.getPlanQty() + plan.getAppendQty();
|
||||
if ((long) before + quantity > total) {
|
||||
if ((long) claim.getProgressQty() + quantity > total) {
|
||||
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.increaseStockedQuantityByClaim(dailyPlanId, quantity, claim.getProgressQty(),
|
||||
normalizedOperator(operator))
|
||||
: dailyPlanMapper.increaseSleevedQuantityByClaim(dailyPlanId, quantity, claim.getProgressQty(),
|
||||
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);
|
||||
throw exception(DAILY_PLAN_CLAIM_PROGRESS_CONFLICT);
|
||||
}
|
||||
insertProgressLog(dailyPlanId, type, before, before + quantity, quantity, operator);
|
||||
}
|
||||
@@ -211,9 +208,11 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void renewClaim(String claimToken, String operator) {
|
||||
validateActiveClaim(claimToken);
|
||||
DailyPlanClaimDO claim = getClaimForUpdate(claimToken);
|
||||
validateActiveClaim(claim);
|
||||
LocalDateTime expireTime = nextClaimExpireTime();
|
||||
if (dailyPlanClaimMapper.renewClaim(claimToken, expireTime, normalizedOperator(operator)) != 1) {
|
||||
if (dailyPlanClaimMapper.renewClaim(claimToken, claim.getVersion(), expireTime,
|
||||
normalizedOperator(operator)) != 1) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
}
|
||||
@@ -236,18 +235,35 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService {
|
||||
return dailyPlanClaimMapper.expireClaims(LocalDateTime.now(), normalizedOperator(operator));
|
||||
}
|
||||
|
||||
private DailyPlanClaimDO validateActiveClaim(String claimToken) {
|
||||
private DailyPlanClaimDO getClaim(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())) {
|
||||
if (claim == null) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
return claim;
|
||||
}
|
||||
|
||||
private DailyPlanClaimDO getClaimForUpdate(String claimToken) {
|
||||
if (StrUtil.isBlank(claimToken)) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
DailyPlanClaimDO claim = dailyPlanClaimMapper.selectByTokenForUpdate(claimToken);
|
||||
if (claim == null) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
return claim;
|
||||
}
|
||||
|
||||
private void validateActiveClaim(DailyPlanClaimDO claim) {
|
||||
if (!Integer.valueOf(CLAIM_ACTIVE).equals(claim.getClaimStatus()) || claim.getActiveFlag() == null
|
||||
|| !claim.getExpireTime().isAfter(LocalDateTime.now())) {
|
||||
throw exception(DAILY_PLAN_CLAIM_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDateTime nextClaimExpireTime() {
|
||||
return LocalDateTime.now().plusSeconds(Math.max(1L, claimTimeoutSeconds));
|
||||
}
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
<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_id, claim_token, daily_plan_id, strategy_type, claimed_qty, plan_version, progress_qty, 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_id, claim_token, daily_plan_id, strategy_type, claimed_qty, plan_version, progress_qty, 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.claimedQty}, #{claim.planVersion}, #{claim.progressQty}, 0, 0, 1, #{claim.expireTime},
|
||||
#{claim.operator}, #{claim.operator}, #{claim.operator})
|
||||
</insert>
|
||||
|
||||
@@ -24,10 +24,17 @@
|
||||
WHERE claim_token = #{claimToken} AND deleted = b'0'
|
||||
</select>
|
||||
|
||||
<select id="selectByTokenForUpdate" 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'
|
||||
FOR UPDATE
|
||||
</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
|
||||
SET claim_status = 1, active_flag = NULL, confirmed_time = NOW(), updater = #{updater}, version = version + 1
|
||||
WHERE claim_id = #{claimId} AND version = #{version} AND claim_status = 0 AND active_flag = 1
|
||||
AND expire_time > NOW() AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
@@ -39,8 +46,8 @@
|
||||
|
||||
<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
|
||||
SET expire_time = #{expireTime}, updater = #{updater}, version = version + 1
|
||||
WHERE claim_token = #{claimToken} AND version = #{version} AND claim_status = 0 AND active_flag = 1
|
||||
AND expire_time > NOW() AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
|
||||
@@ -236,42 +236,42 @@
|
||||
WHERE daily_plan_id = #{dailyPlanId} AND version = #{version} AND deleted = b'0'
|
||||
</update>
|
||||
|
||||
<update id="increaseStockedQuantity">
|
||||
<update id="increaseStockedQuantityByClaim">
|
||||
UPDATE lms_daily_plan
|
||||
SET stocking_status = CASE
|
||||
WHEN stocked_qty + #{incrementQty} = plan_qty + append_qty THEN 2
|
||||
WHEN stocking_status = 1 AND stocked_qty + #{incrementQty} = plan_qty + append_qty THEN 2
|
||||
ELSE stocking_status END,
|
||||
stocking_complete_time = CASE
|
||||
WHEN stocked_qty + #{incrementQty} = plan_qty + append_qty THEN NOW()
|
||||
WHEN stocking_status = 1 AND stocked_qty + #{incrementQty} = plan_qty + append_qty THEN NOW()
|
||||
ELSE stocking_complete_time END,
|
||||
stocked_qty = stocked_qty + #{incrementQty},
|
||||
updater = #{updater},
|
||||
version = version + 1
|
||||
WHERE daily_plan_id = #{dailyPlanId}
|
||||
AND version = #{version}
|
||||
AND deleted = b'0'
|
||||
AND order_status = 1
|
||||
AND stocking_status = 1
|
||||
AND order_status IN (1, 2, 3)
|
||||
AND stocking_status IN (1, 2, 3)
|
||||
AND stocked_qty = #{expectedQty}
|
||||
AND #{incrementQty} > 0
|
||||
AND stocked_qty + #{incrementQty} <= plan_qty + append_qty
|
||||
</update>
|
||||
|
||||
<update id="increaseSleevedQuantity">
|
||||
<update id="increaseSleevedQuantityByClaim">
|
||||
UPDATE lms_daily_plan
|
||||
SET sleeving_status = CASE
|
||||
WHEN sleeved_qty + #{incrementQty} = plan_qty + append_qty THEN 2
|
||||
WHEN sleeving_status = 1 AND sleeved_qty + #{incrementQty} = plan_qty + append_qty THEN 2
|
||||
ELSE sleeving_status END,
|
||||
sleeving_complete_time = CASE
|
||||
WHEN sleeved_qty + #{incrementQty} = plan_qty + append_qty THEN NOW()
|
||||
WHEN sleeving_status = 1 AND sleeved_qty + #{incrementQty} = plan_qty + append_qty THEN NOW()
|
||||
ELSE sleeving_complete_time END,
|
||||
sleeved_qty = sleeved_qty + #{incrementQty},
|
||||
updater = #{updater},
|
||||
version = version + 1
|
||||
WHERE daily_plan_id = #{dailyPlanId}
|
||||
AND version = #{version}
|
||||
AND deleted = b'0'
|
||||
AND order_status = 1
|
||||
AND sleeving_status = 1
|
||||
AND order_status IN (1, 2, 3)
|
||||
AND sleeving_status IN (1, 2, 3)
|
||||
AND sleeved_qty = #{expectedQty}
|
||||
AND #{incrementQty} > 0
|
||||
AND sleeved_qty + #{incrementQty} <= plan_qty + append_qty
|
||||
</update>
|
||||
|
||||
@@ -65,7 +65,9 @@ CREATE TABLE IF NOT EXISTS `lms_daily_plan_claim` (
|
||||
`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 '领取时日计划版本号',
|
||||
`plan_version` int NOT NULL COMMENT '领取时日计划版本号(仅审计,不作为确认并发边界)',
|
||||
`progress_qty` int NOT NULL COMMENT '领取时对应作业已完成数量',
|
||||
`version` int NOT NULL DEFAULT 0 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 '租约过期时间',
|
||||
@@ -108,6 +110,22 @@ SET @lms_daily_plan_ddl = IF(
|
||||
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.columns WHERE table_schema = DATABASE()
|
||||
AND table_name = 'lms_daily_plan_claim' AND column_name = 'progress_qty'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE lms_daily_plan_claim ADD COLUMN progress_qty INT NOT NULL DEFAULT 0 COMMENT ''领取时对应作业已完成数量'' AFTER plan_version');
|
||||
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.columns WHERE table_schema = DATABASE()
|
||||
AND table_name = 'lms_daily_plan_claim' AND column_name = 'version'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE lms_daily_plan_claim ADD COLUMN version INT NOT NULL DEFAULT 0 COMMENT ''领取乐观锁版本号'' AFTER progress_qty');
|
||||
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'),
|
||||
|
||||
Reference in New Issue
Block a user