feat: persist MES delivery point and urgency metadata

This commit is contained in:
zgw
2026-09-08 12:09:13 +08:00
parent 56beeacbfe
commit 1cf4a55ea1
7 changed files with 176 additions and 3 deletions

View File

@@ -0,0 +1,15 @@
# MES 配送申请字段
`insertDeliveryApplication` 的出库配送申请(deliveryDirection=0)保存 `deliveryPoint`,供 WMS 显示配送地点;`requiredTm` 是需求具体时间,为 null、空串或空白时兼容旧字段 `requireTime`;`isExpedited` 为 1(加急)或 0(正常)。以上信息保存至出库单主表,随原有归档流程进入历史表。
例如同一申请可传 `deliveryPoint="哈镘"`、`requiredTm="2026-09-08 15:30:00"`、`isExpedited=1`。旧 MES 请求未传新增信息时仍可接收。
先对共享数据库执行 `sql/20260908_order_management_fields.sql`,再发布 INTERFACE 和配套 WMS。两个仓库提供相同脚本,只需执行一次。迁移补齐业务表和历史表的新增字段,检查新增列的位置/类型与总列数,失败回滚。历史单据以前没有保存的配送地点不会自动补出。
使用 Java 8 构建。离线回归不启动应用、不连接数据库或 MES:
```text
mvn -B -pl ruoyi-admin -am -Dtest=DeliveryApplicationPortServiceTest -Dsurefire.failIfNoSpecifiedTests=false test
```
WMS 的展示、回传状态、托盘码和入库历史查询说明见配套 WMS 的 `docs/order-management-20260908.md`。

View File

@@ -107,6 +107,21 @@ public class OutStockout extends BaseEntity
@Excel(name = "需求时间") @Excel(name = "需求时间")
private String requireTime; private String requireTime;
/** 是否加急:1 加急,0 正常 */
private Integer isExpedited;
/** MES 分配的配送地点 */
@Excel(name = "配送地点")
private String deliveryPoint;
public String getDeliveryPoint() {
return deliveryPoint;
}
public void setDeliveryPoint(String deliveryPoint) {
this.deliveryPoint = deliveryPoint;
}
public String getKdNum() { public String getKdNum() {
return kdNum; return kdNum;
} }
@@ -337,6 +352,14 @@ public class OutStockout extends BaseEntity
this.requireTime = requireTime; this.requireTime = requireTime;
} }
public Integer getIsExpedited() {
return isExpedited;
}
public void setIsExpedited(Integer isExpedited) {
this.isExpedited = isExpedited;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -357,6 +380,7 @@ public class OutStockout extends BaseEntity
.append("finishDate", getFinishDate()) .append("finishDate", getFinishDate())
.append("FID", getFID()) .append("FID", getFID())
.append("erpStockoutId", getErpStockoutId()) .append("erpStockoutId", getErpStockoutId())
.append("isExpedited", getIsExpedited())
.toString(); .toString();
} }
} }

View File

@@ -32,6 +32,10 @@ public class DeliveryApplicationMsg {
private String requester; private String requester;
@Excel(name = "需求时间") @Excel(name = "需求时间")
private String requireTime; private String requireTime;
@Excel(name = "需求时间")
private String requiredTm;
@Excel(name = "是否加急")
private Integer isExpedited;
private String org; private String org;
@@ -67,6 +71,22 @@ public class DeliveryApplicationMsg {
this.requireTime = requireTime; this.requireTime = requireTime;
} }
public String getRequiredTm() {
return requiredTm;
}
public void setRequiredTm(String requiredTm) {
this.requiredTm = requiredTm;
}
public Integer getIsExpedited() {
return isExpedited;
}
public void setIsExpedited(Integer isExpedited) {
this.isExpedited = isExpedited;
}
@Excel(name = "条码集合") @Excel(name = "条码集合")
private List<BarCodeDetail> detailList; private List<BarCodeDetail> detailList;
@@ -176,6 +196,8 @@ public class DeliveryApplicationMsg {
", preparationCode='" + preparationCode + '\'' + ", preparationCode='" + preparationCode + '\'' +
", requester='" + requester + '\'' + ", requester='" + requester + '\'' +
", requireTime='" + requireTime + '\'' + ", requireTime='" + requireTime + '\'' +
", requiredTm='" + requiredTm + '\'' +
", isExpedited=" + isExpedited +
", org='" + org + '\'' + ", org='" + org + '\'' +
", detailList=" + detailList + ", detailList=" + detailList +
'}'; '}';

View File

@@ -1572,8 +1572,14 @@ public class PortServiceImpl implements PortService {
outStockout.setErpStockoutId(deliveryApplicationMsg.getCode()); outStockout.setErpStockoutId(deliveryApplicationMsg.getCode());
// 新加字段 领料人 // 新加字段 领料人
outStockout.setRequester(deliveryApplicationMsg.getRequester()); outStockout.setRequester(deliveryApplicationMsg.getRequester());
outStockout.setDeliveryPoint(deliveryApplicationMsg.getDeliveryPoint());
// 新加字段 需求时间 // 新加字段 需求时间
outStockout.setRequireTime(deliveryApplicationMsg.getRequireTime()); String requiredTm = deliveryApplicationMsg.getRequiredTm();
if (requiredTm == null || requiredTm.trim().isEmpty()) {
requiredTm = deliveryApplicationMsg.getRequireTime();
}
outStockout.setRequireTime(requiredTm);
outStockout.setIsExpedited(deliveryApplicationMsg.getIsExpedited());
outStockoutMapper.insertOutStockout(outStockout); outStockoutMapper.insertOutStockout(outStockout);
OutStockoutDetail outStockoutDetail = new OutStockoutDetail(); OutStockoutDetail outStockoutDetail = new OutStockoutDetail();
outStockoutDetail.setStockoutDetailId(jobId + "-1"); outStockoutDetail.setStockoutDetailId(jobId + "-1");

View File

@@ -29,10 +29,12 @@
<result property="kdNum" column="kd_num" /> <result property="kdNum" column="kd_num" />
<result property="requester" column="requester" /> <result property="requester" column="requester" />
<result property="requireTime" column="require_time" /> <result property="requireTime" column="require_time" />
<result property="isExpedited" column="is_expedited" />
<result property="deliveryPoint" column="delivery_point"/>
</resultMap> </resultMap>
<sql id="selectOutStockoutVo"> <sql id="selectOutStockoutVo">
select stockout_guid, stockout_id, out_type, create_date, department_no, customer_no, create_man_id, status, stockout_source, warehouse_id, class_now_id, exit_id, car_number, FID, erp_stockout_id,bar_code_list,tray_code_list,org,task_id,kd_num,requester,require_time from out_stockout select stockout_guid, stockout_id, out_type, create_date, department_no, customer_no, create_man_id, status, stockout_source, warehouse_id, class_now_id, exit_id, car_number, FID, erp_stockout_id,bar_code_list,tray_code_list,org,task_id,kd_num,requester,require_time,is_expedited,time_ship_plan,delivery_point from out_stockout
</sql> </sql>
<select id="selectOutStockoutList" parameterType="OutStockout" resultMap="OutStockoutResult"> <select id="selectOutStockoutList" parameterType="OutStockout" resultMap="OutStockoutResult">
@@ -93,6 +95,8 @@
<if test="taskId != null">task_id,</if> <if test="taskId != null">task_id,</if>
<if test="requester != null">requester,</if> <if test="requester != null">requester,</if>
<if test="requireTime != null">require_time,</if> <if test="requireTime != null">require_time,</if>
<if test="isExpedited != null">is_expedited,</if>
<if test="deliveryPoint != null">delivery_point,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
@@ -121,6 +125,8 @@
<if test="taskId != null">#{taskId},</if> <if test="taskId != null">#{taskId},</if>
<if test="requester != null">#{requester},</if> <if test="requester != null">#{requester},</if>
<if test="requireTime != null">#{requireTime},</if> <if test="requireTime != null">#{requireTime},</if>
<if test="isExpedited != null">#{isExpedited},</if>
<if test="deliveryPoint != null">#{deliveryPoint},</if>
</trim> </trim>
</insert> </insert>
@@ -142,6 +148,11 @@
<if test="FID != null">FID = #{FID},</if> <if test="FID != null">FID = #{FID},</if>
<if test="erpStockoutId != null">erp_stockout_id = #{erpStockoutId},</if> <if test="erpStockoutId != null">erp_stockout_id = #{erpStockoutId},</if>
<if test="isExpedited != null">is_expedited = #{isExpedited},</if>
<if test="deliveryPoint != null">delivery_point = #{deliveryPoint},</if>
<if test="timeShipPlan != null">time_ship_plan = #{timeShipPlan},</if>
<if test="requester != null">requester = #{requester},</if>
<if test="requireTime != null">require_time = #{requireTime},</if>
</trim> </trim>
where stockout_guid = #{stockoutGuid} where stockout_guid = #{stockoutGuid}
</update> </update>

View File

@@ -0,0 +1,46 @@
package com.ruoyi.web.port;
import com.alibaba.fastjson.JSON;
import com.ruoyi.project.bas.basJobId.service.IBasJobIdService;
import com.ruoyi.project.out.outStock.domain.OutStockout;
import com.ruoyi.project.out.outStock.mapper.OutStockoutMapper;
import com.ruoyi.project.out.outStockDetail.mapper.OutStockoutDetailMapper;
import com.ruoyi.web.port.domain.DeliveryApplicationMsg;
import com.ruoyi.web.port.service.impl.PortServiceImpl;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/** No Spring context, network, scheduler or database: capture the actual persistence boundary. */
class DeliveryApplicationPortServiceTest {
@Test
void preservesMesDeliveryMetadataAndLegacyTime() {
for (String required : new String[]{"2026-09-08 15:30:00", "", " ", null}) {
PortServiceImpl service = new PortServiceImpl();
IBasJobIdService ids = mock(IBasJobIdService.class);
OutStockoutMapper orders = mock(OutStockoutMapper.class);
ReflectionTestUtils.setField(service, "basJobIdService", ids);
ReflectionTestUtils.setField(service, "outStockoutMapper", orders);
ReflectionTestUtils.setField(service, "outStockoutDetailMapper", mock(OutStockoutDetailMapper.class));
when(ids.getJobId("CK")).thenReturn("CK-TEST");
DeliveryApplicationMsg msg = JSON.parseObject("{\"deliveryDirection\":\"0\","
+ "\"code\":\"MES-001\",\"deliveryPoint\":\"哈镘\",\"qtyPlan\":1.25,"
+ "\"requester\":\"叫料人\",\"isExpedited\":1,\"requireTime\":\"2026-09-08 16:00:00\"}",
DeliveryApplicationMsg.class);
msg.setRequiredTm(required);
assertEquals(0, service.insertDeliveryApplication(Collections.singletonList(msg)).getCode());
ArgumentCaptor<OutStockout> captured = ArgumentCaptor.forClass(OutStockout.class);
verify(orders).insertOutStockout(captured.capture());
OutStockout row = captured.getValue();
assertEquals("哈镘", row.getDeliveryPoint());
assertEquals("叫料人", row.getRequester());
assertEquals(Integer.valueOf(1), row.getIsExpedited());
assertEquals("MES-001", row.getErpStockoutId());
assertEquals(required == null || required.trim().isEmpty() ? "2026-09-08 16:00:00" : required,
row.getRequireTime());
}
}
}

View File

@@ -0,0 +1,49 @@
-- WMS / INTERFACE 共用数据库;先执行此脚本,再发布两个应用。
-- 幂等执行。归档存储过程使用 INSERT ... SELECT *,新增列必须在两表相同位置且类型一致。
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
IF OBJECT_ID(N'dbo.out_stockout', N'U') IS NULL
OR OBJECT_ID(N'dbo.out_stockout_finish', N'U') IS NULL
THROW 51000, N'缺少出库业务表或历史表,请核对目标数据库', 1;
IF COL_LENGTH(N'dbo.out_stockout', N'is_expedited') IS NULL
ALTER TABLE dbo.out_stockout ADD is_expedited int NULL;
IF COL_LENGTH(N'dbo.out_stockout_finish', N'is_expedited') IS NULL
ALTER TABLE dbo.out_stockout_finish ADD is_expedited int NULL;
IF COL_LENGTH(N'dbo.out_stockout', N'delivery_point') IS NULL
ALTER TABLE dbo.out_stockout ADD delivery_point nvarchar(100) NULL;
IF COL_LENGTH(N'dbo.out_stockout_finish', N'delivery_point') IS NULL
ALTER TABLE dbo.out_stockout_finish ADD delivery_point nvarchar(100) NULL;
-- 不移动/重建现有列;只验证本次字段的归档位置及总列数,不改动旧字段映射。
IF (SELECT COUNT(*) FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.out_stockout'))
<> (SELECT COUNT(*) FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.out_stockout_finish'))
THROW 51001, N'业务表与历史表列数不同,已回滚;请核对归档映射', 1;
IF EXISTS (
SELECT 1
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY column_id) AS ordinal, name,
system_type_id, max_length, precision, scale
FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.out_stockout')
) a
FULL JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY column_id) AS ordinal, name,
system_type_id, max_length, precision, scale
FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.out_stockout_finish')
) h ON a.ordinal = h.ordinal
WHERE (a.name IN (N'is_expedited', N'delivery_point') OR h.name IN (N'is_expedited', N'delivery_point'))
AND (a.name IS NULL OR h.name IS NULL OR a.name <> h.name
OR a.system_type_id <> h.system_type_id OR a.max_length <> h.max_length
OR a.precision <> h.precision OR a.scale <> h.scale)
)
THROW 51001, N'新增字段在业务表与历史表中的位置或类型不同,已回滚;请核对归档映射', 1;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
THROW;
END CATCH;