feat: add WCS dispatch outbox
This commit is contained in:
@@ -140,6 +140,18 @@ public class MydoJob extends BaseEntity
|
|||||||
/** 通道匹配物料名称(非持久化字段) */
|
/** 通道匹配物料名称(非持久化字段) */
|
||||||
private String productName;
|
private String productName;
|
||||||
|
|
||||||
|
/** WCS 下发状态(非持久化字段) */
|
||||||
|
private String dispatchStatus;
|
||||||
|
|
||||||
|
/** WCS 自动重试次数(非持久化字段) */
|
||||||
|
private Integer autoRetryCount;
|
||||||
|
|
||||||
|
/** WCS 人工下发次数(非持久化字段) */
|
||||||
|
private Integer manualRetryCount;
|
||||||
|
|
||||||
|
/** WCS 最后一次下发错误(非持久化字段) */
|
||||||
|
private String lastDispatchError;
|
||||||
|
|
||||||
public void setJobId(String jobId)
|
public void setJobId(String jobId)
|
||||||
{
|
{
|
||||||
this.jobId = jobId;
|
this.jobId = jobId;
|
||||||
@@ -490,6 +502,46 @@ public class MydoJob extends BaseEntity
|
|||||||
this.productName = productName;
|
this.productName = productName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDispatchStatus()
|
||||||
|
{
|
||||||
|
return dispatchStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDispatchStatus(String dispatchStatus)
|
||||||
|
{
|
||||||
|
this.dispatchStatus = dispatchStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAutoRetryCount()
|
||||||
|
{
|
||||||
|
return autoRetryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoRetryCount(Integer autoRetryCount)
|
||||||
|
{
|
||||||
|
this.autoRetryCount = autoRetryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getManualRetryCount()
|
||||||
|
{
|
||||||
|
return manualRetryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setManualRetryCount(Integer manualRetryCount)
|
||||||
|
{
|
||||||
|
this.manualRetryCount = manualRetryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastDispatchError()
|
||||||
|
{
|
||||||
|
return lastDispatchError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastDispatchError(String lastDispatchError)
|
||||||
|
{
|
||||||
|
this.lastDispatchError = lastDispatchError;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
@@ -529,6 +581,10 @@ public class MydoJob extends BaseEntity
|
|||||||
.append("projectNo", getProjectNo())
|
.append("projectNo", getProjectNo())
|
||||||
.append("productId", getProductId())
|
.append("productId", getProductId())
|
||||||
.append("productName", getProductName())
|
.append("productName", getProductName())
|
||||||
|
.append("dispatchStatus", getDispatchStatus())
|
||||||
|
.append("autoRetryCount", getAutoRetryCount())
|
||||||
|
.append("manualRetryCount", getManualRetryCount())
|
||||||
|
.append("lastDispatchError", getLastDispatchError())
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package com.ruoyi.out.dispatch.domain;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WCS 作业下发记录。
|
||||||
|
*/
|
||||||
|
public class WcsJobDispatch implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static final String PENDING = "PENDING";
|
||||||
|
public static final String SENDING = "SENDING";
|
||||||
|
public static final String BLOCKED = "BLOCKED";
|
||||||
|
public static final String RETRY_WAIT = "RETRY_WAIT";
|
||||||
|
public static final String SUCCESS = "SUCCESS";
|
||||||
|
public static final String EXHAUSTED = "EXHAUSTED";
|
||||||
|
|
||||||
|
private String jobId;
|
||||||
|
private String dispatchStatus;
|
||||||
|
private Integer autoRetryCount;
|
||||||
|
private Integer manualRetryCount;
|
||||||
|
private String lastError;
|
||||||
|
private Date lastAttemptTime;
|
||||||
|
private Date nextRetryTime;
|
||||||
|
private Date successTime;
|
||||||
|
private Integer versionNo;
|
||||||
|
private Date createTime;
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
public String getJobId()
|
||||||
|
{
|
||||||
|
return jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobId(String jobId)
|
||||||
|
{
|
||||||
|
this.jobId = jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDispatchStatus()
|
||||||
|
{
|
||||||
|
return dispatchStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDispatchStatus(String dispatchStatus)
|
||||||
|
{
|
||||||
|
this.dispatchStatus = dispatchStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAutoRetryCount()
|
||||||
|
{
|
||||||
|
return autoRetryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoRetryCount(Integer autoRetryCount)
|
||||||
|
{
|
||||||
|
this.autoRetryCount = autoRetryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getManualRetryCount()
|
||||||
|
{
|
||||||
|
return manualRetryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setManualRetryCount(Integer manualRetryCount)
|
||||||
|
{
|
||||||
|
this.manualRetryCount = manualRetryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastError()
|
||||||
|
{
|
||||||
|
return lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastError(String lastError)
|
||||||
|
{
|
||||||
|
this.lastError = lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLastAttemptTime()
|
||||||
|
{
|
||||||
|
return lastAttemptTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastAttemptTime(Date lastAttemptTime)
|
||||||
|
{
|
||||||
|
this.lastAttemptTime = lastAttemptTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getNextRetryTime()
|
||||||
|
{
|
||||||
|
return nextRetryTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNextRetryTime(Date nextRetryTime)
|
||||||
|
{
|
||||||
|
this.nextRetryTime = nextRetryTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getSuccessTime()
|
||||||
|
{
|
||||||
|
return successTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccessTime(Date successTime)
|
||||||
|
{
|
||||||
|
this.successTime = successTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVersionNo()
|
||||||
|
{
|
||||||
|
return versionNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersionNo(Integer versionNo)
|
||||||
|
{
|
||||||
|
this.versionNo = versionNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreateTime()
|
||||||
|
{
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTime(Date createTime)
|
||||||
|
{
|
||||||
|
this.createTime = createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdateTime()
|
||||||
|
{
|
||||||
|
return updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateTime(Date updateTime)
|
||||||
|
{
|
||||||
|
this.updateTime = updateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.ruoyi.out.dispatch.mapper;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import com.ruoyi.out.dispatch.domain.WcsJobDispatch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WCS 作业下发记录 Mapper。
|
||||||
|
*/
|
||||||
|
public interface WcsJobDispatchMapper
|
||||||
|
{
|
||||||
|
int insertIfAbsent(String jobId);
|
||||||
|
|
||||||
|
WcsJobDispatch selectByJobId(String jobId);
|
||||||
|
|
||||||
|
List<WcsJobDispatch> selectRetryCandidates(@Param("now") Date now, @Param("limit") int limit);
|
||||||
|
|
||||||
|
int claimForSend(Map<String, Object> params);
|
||||||
|
|
||||||
|
int markBlocked(Map<String, Object> params);
|
||||||
|
|
||||||
|
int markRetryWait(Map<String, Object> params);
|
||||||
|
|
||||||
|
int markSuccess(Map<String, Object> params);
|
||||||
|
|
||||||
|
int markExhausted(Map<String, Object> params);
|
||||||
|
}
|
||||||
@@ -36,12 +36,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="supplierName" column="supplier_name" />
|
<result property="supplierName" column="supplier_name" />
|
||||||
<result property="customerId" column="customer_id" />
|
<result property="customerId" column="customer_id" />
|
||||||
<result property="customerName" column="customer_name" />
|
<result property="customerName" column="customer_name" />
|
||||||
|
<result property="dispatchStatus" column="dispatch_status" />
|
||||||
|
<result property="autoRetryCount" column="auto_retry_count" />
|
||||||
|
<result property="manualRetryCount" column="manual_retry_count" />
|
||||||
|
<result property="lastDispatchError" column="last_dispatch_error" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectMydoJobVo">
|
<sql id="selectMydoJobVo">
|
||||||
select job_id, status, task_no, in_or_out, execution_phase, tray_code, warehouse_id,
|
select mydo_job.job_id, status, task_no, in_or_out, execution_phase, tray_code, warehouse_id,
|
||||||
isnull(nullif(warehouse_name, ''), (select top 1 bw.warehouse_name from bas_warehouse bw where bw.warehouse_id = mydo_job.warehouse_id)) as warehouse_name,
|
isnull(nullif(warehouse_name, ''), (select top 1 bw.warehouse_name from bas_warehouse bw where bw.warehouse_id = mydo_job.warehouse_id)) as warehouse_name,
|
||||||
roadway_id, cargo_space_id, cargo_space_name, target_roadway_id, target_cargo_space_id, target_cargo_space_name, line_type, priority, height, weight, create_time, start_time, finish_time, entrance_id, exit_id, dept_id, dept_name, user_id, user_name, supplier_id, supplier_name, customer_id, customer_name from mydo_job
|
roadway_id, cargo_space_id, cargo_space_name, target_roadway_id, target_cargo_space_id, target_cargo_space_name, line_type, priority, height, weight, mydo_job.create_time, start_time, finish_time, entrance_id, exit_id, dept_id, dept_name, user_id, user_name, supplier_id, supplier_name, customer_id, customer_name,
|
||||||
|
wjd.dispatch_status as dispatch_status, wjd.auto_retry_count as auto_retry_count,
|
||||||
|
wjd.manual_retry_count as manual_retry_count, wjd.last_error as last_dispatch_error
|
||||||
|
from mydo_job
|
||||||
|
left join wcs_job_dispatch wjd on wjd.job_id = mydo_job.job_id
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="selectMydoJobFinishVo">
|
<sql id="selectMydoJobFinishVo">
|
||||||
select job_id, status, task_no, in_or_out, execution_phase, tray_code, warehouse_id,
|
select job_id, status, task_no, in_or_out, execution_phase, tray_code, warehouse_id,
|
||||||
@@ -79,7 +87,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
|
|
||||||
<select id="selectMydoJobByJobId" parameterType="String" resultMap="MydoJobResult">
|
<select id="selectMydoJobByJobId" parameterType="String" resultMap="MydoJobResult">
|
||||||
<include refid="selectMydoJobVo"/>
|
<include refid="selectMydoJobVo"/>
|
||||||
where job_id = #{jobId}
|
where mydo_job.job_id = #{jobId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="acquirePutOccupiedJobLock" parameterType="java.util.Map" resultType="java.lang.Integer">
|
<select id="acquirePutOccupiedJobLock" parameterType="java.util.Map" resultType="java.lang.Integer">
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<?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="com.ruoyi.out.dispatch.mapper.WcsJobDispatchMapper">
|
||||||
|
|
||||||
|
<resultMap type="com.ruoyi.out.dispatch.domain.WcsJobDispatch" id="WcsJobDispatchResult">
|
||||||
|
<id property="jobId" column="job_id" />
|
||||||
|
<result property="dispatchStatus" column="dispatch_status" />
|
||||||
|
<result property="autoRetryCount" column="auto_retry_count" />
|
||||||
|
<result property="manualRetryCount" column="manual_retry_count" />
|
||||||
|
<result property="lastError" column="last_error" />
|
||||||
|
<result property="lastAttemptTime" column="last_attempt_time" />
|
||||||
|
<result property="nextRetryTime" column="next_retry_time" />
|
||||||
|
<result property="successTime" column="success_time" />
|
||||||
|
<result property="versionNo" column="version_no" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<insert id="insertIfAbsent" parameterType="String">
|
||||||
|
if not exists (select 1 from wcs_job_dispatch with (updlock, holdlock) where job_id = #{jobId})
|
||||||
|
begin
|
||||||
|
insert into wcs_job_dispatch
|
||||||
|
(job_id, dispatch_status, auto_retry_count, manual_retry_count, version_no, create_time, update_time)
|
||||||
|
values
|
||||||
|
(#{jobId}, 'PENDING', 0, 0, 0, getdate(), getdate())
|
||||||
|
end
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectByJobId" parameterType="String" resultMap="WcsJobDispatchResult">
|
||||||
|
select job_id, dispatch_status, auto_retry_count, manual_retry_count, last_error,
|
||||||
|
last_attempt_time, next_retry_time, success_time, version_no, create_time, update_time
|
||||||
|
from wcs_job_dispatch
|
||||||
|
where job_id = #{jobId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectRetryCandidates" resultMap="WcsJobDispatchResult">
|
||||||
|
select top (#{limit}) job_id, dispatch_status, auto_retry_count, manual_retry_count, last_error,
|
||||||
|
last_attempt_time, next_retry_time, success_time, version_no, create_time, update_time
|
||||||
|
from wcs_job_dispatch with (readpast)
|
||||||
|
where (dispatch_status = 'RETRY_WAIT'
|
||||||
|
and auto_retry_count < 5
|
||||||
|
and (next_retry_time is null or next_retry_time <= #{now}))
|
||||||
|
or dispatch_status = 'BLOCKED'
|
||||||
|
or (dispatch_status = 'SENDING'
|
||||||
|
and last_attempt_time <= dateadd(minute, -5, #{now}))
|
||||||
|
order by create_time, job_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="claimForSend" parameterType="map">
|
||||||
|
update wcs_job_dispatch
|
||||||
|
set dispatch_status = 'SENDING',
|
||||||
|
auto_retry_count = auto_retry_count + case when #{trigger} = 'AUTO_RETRY' then 1 else 0 end,
|
||||||
|
manual_retry_count = manual_retry_count + case when #{trigger} = 'MANUAL' then 1 else 0 end,
|
||||||
|
last_attempt_time = #{attemptTime},
|
||||||
|
next_retry_time = null,
|
||||||
|
update_time = #{attemptTime},
|
||||||
|
version_no = version_no + 1
|
||||||
|
where job_id = #{jobId}
|
||||||
|
and version_no = #{versionNo}
|
||||||
|
and dispatch_status in ('PENDING', 'BLOCKED', 'RETRY_WAIT', 'EXHAUSTED', 'SENDING')
|
||||||
|
and (#{trigger} != 'AUTO_RETRY' or auto_retry_count < 5)
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="markBlocked" parameterType="map">
|
||||||
|
update wcs_job_dispatch
|
||||||
|
set dispatch_status = 'BLOCKED', last_error = #{lastError}, next_retry_time = #{nextRetryTime},
|
||||||
|
update_time = #{updateTime}, version_no = version_no + 1
|
||||||
|
where job_id = #{jobId} and dispatch_status != 'SUCCESS'
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="markRetryWait" parameterType="map">
|
||||||
|
update wcs_job_dispatch
|
||||||
|
set dispatch_status = 'RETRY_WAIT', last_error = #{lastError}, next_retry_time = #{nextRetryTime},
|
||||||
|
update_time = #{updateTime}, version_no = version_no + 1
|
||||||
|
where job_id = #{jobId} and dispatch_status = 'SENDING'
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="markSuccess" parameterType="map">
|
||||||
|
update wcs_job_dispatch
|
||||||
|
set dispatch_status = 'SUCCESS', last_error = null, next_retry_time = null,
|
||||||
|
success_time = #{successTime}, update_time = #{successTime}, version_no = version_no + 1
|
||||||
|
where job_id = #{jobId} and dispatch_status = 'SENDING'
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="markExhausted" parameterType="map">
|
||||||
|
update wcs_job_dispatch
|
||||||
|
set dispatch_status = 'EXHAUSTED', last_error = #{lastError}, next_retry_time = null,
|
||||||
|
update_time = #{updateTime}, version_no = version_no + 1
|
||||||
|
where job_id = #{jobId} and dispatch_status = 'SENDING'
|
||||||
|
</update>
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package com.ruoyi.out.dispatch.mapper;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class WcsJobDispatchMapperSqlTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
void dispatchMapperDefinesDurableRetryStateTransitions() throws Exception
|
||||||
|
{
|
||||||
|
String xml = Files.readString(resolvePath(
|
||||||
|
"src/main/resources/mapper/out/WcsJobDispatchMapper.xml",
|
||||||
|
"ruoyi-admin/src/main/resources/mapper/out/WcsJobDispatchMapper.xml"));
|
||||||
|
|
||||||
|
assertThat(xml)
|
||||||
|
.contains("PENDING")
|
||||||
|
.contains("SENDING")
|
||||||
|
.contains("BLOCKED")
|
||||||
|
.contains("RETRY_WAIT")
|
||||||
|
.contains("SUCCESS")
|
||||||
|
.contains("EXHAUSTED")
|
||||||
|
.contains("auto_retry_count < 5")
|
||||||
|
.contains("dispatch_status = 'SENDING'")
|
||||||
|
.contains("version_no = version_no + 1")
|
||||||
|
.contains("selectRetryCandidates")
|
||||||
|
.contains("claimForSend")
|
||||||
|
.contains("markRetryWait")
|
||||||
|
.contains("markExhausted");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void migrationCreatesRetryTaskRelocationTypeAndDenseLaneMenu() throws Exception
|
||||||
|
{
|
||||||
|
String sql = Files.readString(resolvePath(
|
||||||
|
"../sql/20260716_dense_outbound_relocation_dispatch.sql",
|
||||||
|
"sql/20260716_dense_outbound_relocation_dispatch.sql"));
|
||||||
|
|
||||||
|
assertThat(sql)
|
||||||
|
.contains("CREATE TABLE dbo.wcs_job_dispatch")
|
||||||
|
.contains("IF NOT EXISTS")
|
||||||
|
.contains("auto_retry_count")
|
||||||
|
.contains("manual_retry_count")
|
||||||
|
.contains("last_error")
|
||||||
|
.contains("wcsOutboundRetryTask.retryFailedJobs")
|
||||||
|
.contains("0 0/1 * * * ?")
|
||||||
|
.contains("out:denseLaneOutbound:list")
|
||||||
|
.contains("out:denseLaneOutbound:preview")
|
||||||
|
.contains("out:denseLaneOutbound:generate")
|
||||||
|
.contains("out:job:pushWcs")
|
||||||
|
.contains("N'23'")
|
||||||
|
.contains("N'移库'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void outboundJobQueriesExposeDispatchState() throws Exception
|
||||||
|
{
|
||||||
|
String xml = Files.readString(resolvePath(
|
||||||
|
"src/main/resources/mapper/in/MydoJobMapper.xml",
|
||||||
|
"ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml"));
|
||||||
|
|
||||||
|
assertThat(xml)
|
||||||
|
.contains("left join wcs_job_dispatch")
|
||||||
|
.contains("dispatchStatus")
|
||||||
|
.contains("autoRetryCount")
|
||||||
|
.contains("manualRetryCount")
|
||||||
|
.contains("lastDispatchError");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path resolvePath(String modulePath, String rootPath)
|
||||||
|
{
|
||||||
|
return Stream.of(Path.of(modulePath), Path.of(rootPath))
|
||||||
|
.filter(Files::exists)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
280
sql/20260716_dense_outbound_relocation_dispatch.sql
Normal file
280
sql/20260716_dense_outbound_relocation_dispatch.sql
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
-- 密集库出库、移库及 WCS 下发补偿
|
||||||
|
-- 目标库:FTC25009-WMS
|
||||||
|
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
IF OBJECT_ID(N'dbo.wcs_job_dispatch', N'U') IS NULL
|
||||||
|
BEGIN
|
||||||
|
CREATE TABLE dbo.wcs_job_dispatch
|
||||||
|
(
|
||||||
|
job_id nvarchar(255) NOT NULL,
|
||||||
|
dispatch_status nvarchar(20) NOT NULL CONSTRAINT DF_wcs_job_dispatch_status DEFAULT N'PENDING',
|
||||||
|
auto_retry_count int NOT NULL CONSTRAINT DF_wcs_job_dispatch_auto_retry DEFAULT 0,
|
||||||
|
manual_retry_count int NOT NULL CONSTRAINT DF_wcs_job_dispatch_manual_retry DEFAULT 0,
|
||||||
|
last_error nvarchar(1000) NULL,
|
||||||
|
last_attempt_time datetime2 NULL,
|
||||||
|
next_retry_time datetime2 NULL,
|
||||||
|
success_time datetime2 NULL,
|
||||||
|
version_no int NOT NULL CONSTRAINT DF_wcs_job_dispatch_version DEFAULT 0,
|
||||||
|
create_time datetime2 NOT NULL CONSTRAINT DF_wcs_job_dispatch_create_time DEFAULT SYSDATETIME(),
|
||||||
|
update_time datetime2 NOT NULL CONSTRAINT DF_wcs_job_dispatch_update_time DEFAULT SYSDATETIME(),
|
||||||
|
CONSTRAINT PK_wcs_job_dispatch PRIMARY KEY CLUSTERED (job_id),
|
||||||
|
CONSTRAINT CK_wcs_job_dispatch_status CHECK
|
||||||
|
(dispatch_status IN (N'PENDING', N'SENDING', N'BLOCKED', N'RETRY_WAIT', N'SUCCESS', N'EXHAUSTED')),
|
||||||
|
CONSTRAINT CK_wcs_job_dispatch_auto_retry CHECK (auto_retry_count BETWEEN 0 AND 5),
|
||||||
|
CONSTRAINT CK_wcs_job_dispatch_manual_retry CHECK (manual_retry_count >= 0)
|
||||||
|
);
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF NOT EXISTS
|
||||||
|
(
|
||||||
|
SELECT 1 FROM sys.indexes
|
||||||
|
WHERE object_id = OBJECT_ID(N'dbo.wcs_job_dispatch')
|
||||||
|
AND name = N'IX_wcs_job_dispatch_retry'
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
CREATE NONCLUSTERED INDEX IX_wcs_job_dispatch_retry
|
||||||
|
ON dbo.wcs_job_dispatch (dispatch_status, next_retry_time, auto_retry_count, create_time)
|
||||||
|
INCLUDE (version_no);
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF NOT EXISTS
|
||||||
|
(
|
||||||
|
SELECT 1 FROM sys.indexes
|
||||||
|
WHERE object_id = OBJECT_ID(N'dbo.mydo_job')
|
||||||
|
AND name = N'IX_mydo_job_dense_dispatch'
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
CREATE NONCLUSTERED INDEX IX_mydo_job_dense_dispatch
|
||||||
|
ON dbo.mydo_job (warehouse_id, cargo_space_id, in_or_out, status, execution_phase)
|
||||||
|
INCLUDE (job_id, tray_code, task_no);
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM dbo.bas_task_no WHERE id = N'23')
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO dbo.bas_task_no (id, task_type, type_name, task_no, min_no, max_no)
|
||||||
|
VALUES (N'23', N'23', N'移库', 90000, 90001, 99999);
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
UPDATE dbo.bas_task_no
|
||||||
|
SET task_type = N'23', type_name = N'移库'
|
||||||
|
WHERE id = N'23';
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
DECLARE @retryJobId bigint;
|
||||||
|
DECLARE @retryJobIdIsIdentity bit = COLUMNPROPERTY(OBJECT_ID(N'dbo.sys_job'), 'job_id', 'IsIdentity');
|
||||||
|
|
||||||
|
SELECT TOP 1 @retryJobId = job_id
|
||||||
|
FROM dbo.sys_job
|
||||||
|
WHERE invoke_target = N'wcsOutboundRetryTask.retryFailedJobs()';
|
||||||
|
|
||||||
|
IF @retryJobId IS NULL
|
||||||
|
BEGIN
|
||||||
|
SELECT @retryJobId = ISNULL(MAX(job_id), 0) + 1 FROM dbo.sys_job;
|
||||||
|
|
||||||
|
IF @retryJobIdIsIdentity = 1
|
||||||
|
SET IDENTITY_INSERT dbo.sys_job ON;
|
||||||
|
|
||||||
|
INSERT INTO dbo.sys_job
|
||||||
|
(
|
||||||
|
job_id, job_name, job_group, invoke_target, cron_expression,
|
||||||
|
misfire_policy, concurrent, status, create_by, create_time, update_by, update_time, remark
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@retryJobId, N'WCS出库下发失败补偿', N'DEFAULT', N'wcsOutboundRetryTask.retryFailedJobs()', N'0 0/1 * * * ?',
|
||||||
|
N'3', N'1', N'0', N'admin', GETDATE(), N'', NULL, N'每分钟补偿失败或被密集库遮挡的出库作业'
|
||||||
|
);
|
||||||
|
|
||||||
|
IF @retryJobIdIsIdentity = 1
|
||||||
|
SET IDENTITY_INSERT dbo.sys_job OFF;
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
UPDATE dbo.sys_job
|
||||||
|
SET job_name = N'WCS出库下发失败补偿',
|
||||||
|
job_group = N'DEFAULT',
|
||||||
|
cron_expression = N'0 0/1 * * * ?',
|
||||||
|
misfire_policy = N'3',
|
||||||
|
concurrent = N'1',
|
||||||
|
status = N'0',
|
||||||
|
update_by = N'admin',
|
||||||
|
update_time = GETDATE(),
|
||||||
|
remark = N'每分钟补偿失败或被密集库遮挡的出库作业'
|
||||||
|
WHERE job_id = @retryJobId;
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
DECLARE @outMenuId bigint;
|
||||||
|
DECLARE @denseMenuId bigint;
|
||||||
|
DECLARE @previewMenuId bigint;
|
||||||
|
DECLARE @generateMenuId bigint;
|
||||||
|
DECLARE @outJobMenuId bigint;
|
||||||
|
DECLARE @pushWcsMenuId bigint;
|
||||||
|
DECLARE @menuIdIsIdentity bit = COLUMNPROPERTY(OBJECT_ID(N'dbo.sys_menu'), 'menu_id', 'IsIdentity');
|
||||||
|
|
||||||
|
SELECT TOP 1 @outMenuId = menu_id
|
||||||
|
FROM dbo.sys_menu
|
||||||
|
WHERE menu_type = N'M' AND (path = N'out' OR menu_name = N'出库管理')
|
||||||
|
ORDER BY CASE WHEN menu_id = 2001 THEN 0 ELSE 1 END, menu_id;
|
||||||
|
|
||||||
|
IF @outMenuId IS NULL
|
||||||
|
SET @outMenuId = 2001;
|
||||||
|
|
||||||
|
SELECT TOP 1 @denseMenuId = menu_id
|
||||||
|
FROM dbo.sys_menu
|
||||||
|
WHERE menu_type = N'C'
|
||||||
|
AND (perms = N'out:denseLaneOutbound:list'
|
||||||
|
OR (path = N'denseLaneOutbound' AND component = N'out/denseLaneOutbound/index'));
|
||||||
|
|
||||||
|
IF @denseMenuId IS NULL
|
||||||
|
BEGIN
|
||||||
|
SELECT @denseMenuId = ISNULL(MAX(menu_id), 2200) + 1 FROM dbo.sys_menu;
|
||||||
|
END
|
||||||
|
|
||||||
|
SELECT TOP 1 @previewMenuId = menu_id
|
||||||
|
FROM dbo.sys_menu
|
||||||
|
WHERE menu_type = N'F' AND perms = N'out:denseLaneOutbound:preview';
|
||||||
|
|
||||||
|
IF @previewMenuId IS NULL
|
||||||
|
BEGIN
|
||||||
|
SELECT @previewMenuId = ISNULL(MAX(menu_id), @denseMenuId) + 1 FROM dbo.sys_menu;
|
||||||
|
WHILE @previewMenuId IN (@denseMenuId) OR EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @previewMenuId)
|
||||||
|
SET @previewMenuId = @previewMenuId + 1;
|
||||||
|
END
|
||||||
|
|
||||||
|
SELECT TOP 1 @generateMenuId = menu_id
|
||||||
|
FROM dbo.sys_menu
|
||||||
|
WHERE menu_type = N'F' AND perms = N'out:denseLaneOutbound:generate';
|
||||||
|
|
||||||
|
IF @generateMenuId IS NULL
|
||||||
|
BEGIN
|
||||||
|
SET @generateMenuId = @previewMenuId + 1;
|
||||||
|
WHILE @generateMenuId IN (@denseMenuId, @previewMenuId) OR EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @generateMenuId)
|
||||||
|
SET @generateMenuId = @generateMenuId + 1;
|
||||||
|
END
|
||||||
|
|
||||||
|
SELECT TOP 1 @outJobMenuId = menu_id
|
||||||
|
FROM dbo.sys_menu
|
||||||
|
WHERE menu_type = N'C' AND perms = N'out:job:list'
|
||||||
|
ORDER BY menu_id;
|
||||||
|
|
||||||
|
SELECT TOP 1 @pushWcsMenuId = menu_id
|
||||||
|
FROM dbo.sys_menu
|
||||||
|
WHERE menu_type = N'F' AND perms = N'out:job:pushWcs';
|
||||||
|
|
||||||
|
IF @pushWcsMenuId IS NULL
|
||||||
|
BEGIN
|
||||||
|
SET @pushWcsMenuId = @generateMenuId + 1;
|
||||||
|
WHILE @pushWcsMenuId IN (@denseMenuId, @previewMenuId, @generateMenuId)
|
||||||
|
OR EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @pushWcsMenuId)
|
||||||
|
SET @pushWcsMenuId = @pushWcsMenuId + 1;
|
||||||
|
END
|
||||||
|
|
||||||
|
IF @menuIdIsIdentity = 1
|
||||||
|
SET IDENTITY_INSERT dbo.sys_menu ON;
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @denseMenuId)
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO dbo.sys_menu
|
||||||
|
(
|
||||||
|
menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
|
||||||
|
is_frame, is_cache, menu_type, visible, status, perms, icon,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@denseMenuId, N'指定通道出库', @outMenuId, 5, N'denseLaneOutbound', N'out/denseLaneOutbound/index', NULL, N'',
|
||||||
|
1, 0, N'C', N'0', N'0', N'out:denseLaneOutbound:list', N'table',
|
||||||
|
N'admin', GETDATE(), N'', NULL, N'03仓密集库按通道生成端头托盘出库作业'
|
||||||
|
);
|
||||||
|
END
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
UPDATE dbo.sys_menu
|
||||||
|
SET menu_name = N'指定通道出库', parent_id = @outMenuId, order_num = 5,
|
||||||
|
path = N'denseLaneOutbound', component = N'out/denseLaneOutbound/index',
|
||||||
|
perms = N'out:denseLaneOutbound:list', icon = N'table', visible = N'0', status = N'0',
|
||||||
|
update_by = N'admin', update_time = GETDATE()
|
||||||
|
WHERE menu_id = @denseMenuId;
|
||||||
|
END
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @previewMenuId)
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO dbo.sys_menu
|
||||||
|
(
|
||||||
|
menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
|
||||||
|
is_frame, is_cache, menu_type, visible, status, perms, icon,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@previewMenuId, N'预览通道出库', @denseMenuId, 1, N'#', N'', NULL, N'',
|
||||||
|
1, 0, N'F', N'0', N'0', N'out:denseLaneOutbound:preview', N'#',
|
||||||
|
N'admin', GETDATE(), N'', NULL, N''
|
||||||
|
);
|
||||||
|
END
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @generateMenuId)
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO dbo.sys_menu
|
||||||
|
(
|
||||||
|
menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
|
||||||
|
is_frame, is_cache, menu_type, visible, status, perms, icon,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@generateMenuId, N'生成通道出库', @denseMenuId, 2, N'#', N'', NULL, N'',
|
||||||
|
1, 0, N'F', N'0', N'0', N'out:denseLaneOutbound:generate', N'#',
|
||||||
|
N'admin', GETDATE(), N'', NULL, N''
|
||||||
|
);
|
||||||
|
END
|
||||||
|
|
||||||
|
IF @outJobMenuId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.sys_menu WHERE menu_id = @pushWcsMenuId)
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO dbo.sys_menu
|
||||||
|
(
|
||||||
|
menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
|
||||||
|
is_frame, is_cache, menu_type, visible, status, perms, icon,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@pushWcsMenuId, N'手动下发WCS', @outJobMenuId, 6, N'#', N'', NULL, N'',
|
||||||
|
1, 0, N'F', N'0', N'0', N'out:job:pushWcs', N'#',
|
||||||
|
N'admin', GETDATE(), N'', NULL, N''
|
||||||
|
);
|
||||||
|
END
|
||||||
|
|
||||||
|
IF @menuIdIsIdentity = 1
|
||||||
|
SET IDENTITY_INSERT dbo.sys_menu OFF;
|
||||||
|
|
||||||
|
IF OBJECT_ID(N'dbo.sys_role_menu', N'U') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO dbo.sys_role_menu (role_id, menu_id)
|
||||||
|
SELECT DISTINCT rm.role_id, permission_menu.menu_id
|
||||||
|
FROM dbo.sys_role_menu rm
|
||||||
|
CROSS APPLY (VALUES (@denseMenuId), (@previewMenuId), (@generateMenuId)) permission_menu(menu_id)
|
||||||
|
WHERE rm.menu_id = @outMenuId
|
||||||
|
AND NOT EXISTS
|
||||||
|
(SELECT 1 FROM dbo.sys_role_menu current_rm
|
||||||
|
WHERE current_rm.role_id = rm.role_id AND current_rm.menu_id = permission_menu.menu_id);
|
||||||
|
|
||||||
|
IF @outJobMenuId IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO dbo.sys_role_menu (role_id, menu_id)
|
||||||
|
SELECT DISTINCT rm.role_id, @pushWcsMenuId
|
||||||
|
FROM dbo.sys_role_menu rm
|
||||||
|
WHERE rm.menu_id = @outJobMenuId
|
||||||
|
AND NOT EXISTS
|
||||||
|
(SELECT 1 FROM dbo.sys_role_menu current_rm
|
||||||
|
WHERE current_rm.role_id = rm.role_id AND current_rm.menu_id = @pushWcsMenuId);
|
||||||
|
END
|
||||||
|
END
|
||||||
|
GO
|
||||||
Reference in New Issue
Block a user