跳到主要内容

12. Order 服务

通过 client.order() 进行访问。工作指令 (Work Order) 从创建 → 开始 → 中断/恢复 → 结束的整个生命周期由基于 ISA-88 的状态机进行管理。

11.1 工作指令状态 (基于 ISA-88)​

CREATE → WAIT ──start()──► START ──pause()──► PAUSED
│ │
│ resume()
│ │
▼ ▼
END ◄──end()──── START
│
└─ (또는) ──abort()──► ABORTED
状态 (status)含义迁移方法ISA-95 状态 (isa95_state)
WAIT等待 (创建后的初始状态)create() 结果Ready
START进行中start(), resume()Running
PAUSED暂停pause()Held
END正常完成end()Completed
ABORTED异常结束abort()Aborted

status 为存储值本身,仅限上述五种。未开始即取消的工作指令并非新状态,而是 ABORTED + abort_code=CANCELLED。工作指令行 (/order·列表·/order/query)、业绩文档和 plantpulse.order.* 事件在此基础上附加 ISA-95 Part 4 工作指令状态 isa95_state — 其对应关系见上表,所有路径产生相同的值。

无法进行状态迁移的调用(例如:在已处于 START 状态时重新调用 start()),服务器将发送 OK + data.success=false 响应,V5 方法将返回 false。

11.2 方法一览​

CRUD​

方法返回类型HTTP端点
create(OrderRequestV5)OrderResponseV5 或 nullPOST/api/v5/order
update(order_id, OrderRequestV5)OrderResponseV5 或 nullPUT/api/v5/order/{id}
delete(order_id)booleanDELETE/api/v5/order/{id}
get(order_id)OrderResponseV5 或 nullGET/api/v5/order/{id}
list()List<OrderResponseV5>GET/api/v5/order
exists(order_id)booleanGET/api/v5/order/{id}/exists

生命周期 (均返回 boolean)​

方法HTTP端点
start(order_id)POST/api/v5/order/{id}/start
end(order_id)POST/api/v5/order/{id}/end
pause(order_id)POST/api/v5/order/{id}/pause
resume(order_id)POST/api/v5/order/{id}/resume
abort(order_id)POST/api/v5/order/{id}/abort

11.3 OrderRequestV5 / OrderResponseV5​

字段类型说明
order_idString工作指令 ID (PK)
order_nameString工作指令名称 — 必填,不可为空 (422 order.name.required)。B2MML JobOrder 的名称
descriptionString说明
site_idString所属站点
asset_idString目标资产 (Equipment)
customer_idString客户 (可选)
product_idString生产产品
employee_idString负责员工 (可选)
planned_quantityQuantity计划数量 — ISA-95 / B2MML QuantityValueType。详见下方 11.5 数量
time_per_unit_in_mslong单位标准时间
planned_start_timestamplong计划开始时间 (毫秒)
planned_end_timestamplong计划结束时间 (毫秒)
external_idString外部系统 (MES·ERP) 的工作指令编号 (最高 100 字)。与 external_system 构成配对进行识别 — 11.6
external_systemString发布该工作指令的外部系统名称 (最高 50 字) — 外部识别配对的另一半
customer_po_idString此工作指令对应的客户采购订单 (PO) 编号 (可选)
statusString(仅响应) 当前状态 — 存储值 WAIT·START·PAUSED·END·ABORTED
isa95_stateString(仅响应) ISA-95 工作指令状态 — Ready·Running·Held·Completed·Aborted (11.1)
名称已于 2026.11 变更 — 无别名

title → order_name, fix_start_timestamp·fix_end_timestamp → planned_start_timestamp·planned_end_timestamp, external_order_id → external_id, external_po_id → customer_po_id。旧名称将不再在请求中读取,也不会在响应中出现 — 升级指南。

11.4 使用示例​

创建工作指令​

import plantpulse.api.v5.dto.Quantity;
import plantpulse.api.v5.dto.request.OrderRequestV5;
import plantpulse.api.v5.dto.response.OrderResponseV5;

OrderRequestV5 req = new OrderRequestV5();
req.setOrder_id("ORDER_000001");
req.setOrder_name("5월 14일 1교대 생산");
req.setDescription("PROD_A001 500개 생산");
req.setSite_id("SITE_DJ");
req.setAsset_id("ASSET_DJ_M_0001");
req.setProduct_id("PROD_A001");
req.setCustomer_id("CUST_001");
req.setEmployee_id("EMP_E12345");
req.setPlanned_quantity(Quantity.of("500", "EA")); // 값은 10진 «문자열», 단위는 UN/ECE Rec 20 코드
req.setTime_per_unit_in_ms(5_000);

long now = System.currentTimeMillis();
req.setPlanned_start_timestamp(now);
req.setPlanned_end_timestamp(now + 4 * 3600_000L);
req.setExternal_id("MES-2026-0514-001");
req.setExternal_system("MES");

OrderResponseV5 created = client.order().create(req);

标准生命周期​

String orderId = "ORDER_000001";

// WAIT → START
if (!client.order().start(orderId)) {
System.err.println("시작 실패 — planned_start_timestamp가 미래이거나 이미 진행중");
return;
}

// 잠시 후 — 일시중지
client.order().pause(orderId);

// 재개
client.order().resume(orderId);

// 정상 종료
client.order().end(orderId);

异常结束​

// abort 는 별도 인자 없이 호출. 상세 사유는 update() 로 description/notes 에 기록.
if (!client.order().abort("ORDER_000001")) {
System.err.println("중단 실패");
}

单条查询 / 存在确认​

OrderResponseV5 o = client.order().get("ORDER_000001");
if (o != null) {
System.out.println("상태: " + o.getStatus());
Quantity planned = o.getPlanned_quantity(); // {quantity_string, data_type, unit_of_measure}
System.out.println("계획: " + planned.getQuantity_string() + " " + planned.getUnit_of_measure());
java.math.BigDecimal value = planned.toBigDecimal(); // 계산은 BigDecimal 로 — double 로 바꾸지 않는다
}

boolean exists = client.order().exists("ORDER_000001");

全部列表​

import java.util.List;

List<OrderResponseV5> all = client.order().list();
for (OrderResponseV5 o : all) {
System.out.printf("[%s] %s — %s%n",
o.getStatus(), o.getOrder_id(), o.getOrder_name());
}

仅进行中的工作指令 (客户端侧过滤)​

import java.util.stream.Collectors;

List<OrderResponseV5> active = client.order().list().stream()
.filter(o -> "START".equals(o.getStatus())
|| "PAUSE".equals(o.getStatus()))
.collect(Collectors.toList());

按资产查询工作指令​

String assetId = "ASSET_DJ_M_0001";
List<OrderResponseV5> assetOrders = client.order().list().stream()
.filter(o -> assetId.equals(o.getAsset_id()))
.collect(Collectors.toList());

按状态统计​

import java.util.Map;

Map<String, Long> byStatus = client.order().list().stream()
.collect(Collectors.groupingBy(
OrderResponseV5::getStatus,
Collectors.counting()));

byStatus.forEach((status, count) ->
System.out.printf("%s: %d건%n", status, count));

修改 / 删除​

// 수정 (계획 시간 연장)
OrderRequestV5 update = new OrderRequestV5();
update.setOrder_id("ORDER_000001");
update.setOrder_name("5월 14일 1교대 생산 (연장)");
// ... 모든 필드 다시 세팅 ...
update.setPlanned_end_timestamp(System.currentTimeMillis() + 8 * 3600_000L);
client.order().update("ORDER_000001", update);

// 삭제 (취소 처리)
client.order().delete("ORDER_000001");

11.5 数量 — ISA-95 Quantity​

工作指令的数量(计划·生产·良品·报废·返工 …)并非单一数字,而是包含值和单位的对象。 其形式与 ISA-95 (IEC 62264) / B2MML V0700 的 QuantityValueType 保持 1:1 对应。

本节适用的版本

基于 V5 API (OpenAPI info.version 5.0) · 数量协议 2026-10-30 · 名称 Wave 2026-10-31 · Platform 2026.11 版本 (server-web 974891b4)。 事件为 plantpulse.order.*·plantpulse.calendar.* 架构 major 2, plantpulse.kpi.oee.finalized major 1, DB 为 Flyway V99·V100·V103 及 core 迁移 V12V16·V21V23 — 升级指南。

[
{ "quantity_string": "1250.5", "data_type": "decimal", "unit_of_measure": "KGM" },
{ "quantity_string": "1200", "data_type": "integer", "unit_of_measure": "EA" }
]
字段B2MML类型规则
quantity_stringQuantityStringstring采用 10 进制表示 — 禁止指数表示,小数点为 .,最高保留至小数点后第四位。计数单位必须为整数
data_typeDataTypestringinteger (计数单位) 或 decimal (其他)。由服务器根据单位确定 — 请求中可省略,若提供则必须与单位匹配
unit_of_measureUnitOfMeasurestringUN/ECE Recommendation 20 通用代码 — 见下方允许列表
值为何使用字符串

因为 B2MML 将其定义为 QuantityString,且大多数 JSON 解析器将数字读取为 double 导致失去 10 进制精度。在 SDK 中请使用 Quantity.toBigDecimal() 读取并进行计算。在创建请求时, Quantity.of("1250.5", "KGM") — 若 data_type 为空,服务器将自动填充。

单位 — 允许列表 (UN/ECE Rec 20)​

代码含义data_type界面符号
EAeach — 个数integerEA
H87pieceintegerpc
C62one (unit)integerunit
BXbox — 箱数integerbox
SETset — 套/组件数integerset
KGMkilogramdecimalkg
GRMgramdecimalg
TNEtonnedecimalt
LTRlitredecimalL
MLTmillilitredecimalmL
MTQcubic metredecimalm³
MTRmetredecimalm
MTKsquare metredecimalm²
  • 允许单位共 13 个,其中计数单位为 EA·H87·C62·BX·SET 这五个。列表之外的代码将被拒绝 (quantity.unit_invalid)。 代码比对区分大小写 — ea, KG, PCS 均非允许代码。
  • 若输入列表中不存在的界面符号代码(例如旧数据),将原样显示代码。
  • 不进行单位换算(单位主数据及换算由 MES 负责)。不同单位的数量不得相加。
  • 界面符号与语言无关 — 即使在中文界面中也显示 EA 而非 «个»。符号始终紧跟数值(包括个数)。

字段名称 — ISO 22400​

字段名称遵循 ISA-95 和 ISO 22400-2 (IEC 62264 的 KPI 对应项) 的术语。旧名称不再出现在响应中(无兼容字段)。

含义字段 (Quantity)旧字段依据
计划数量planned_quantitytarget_units + unitISA-95 MaterialRequirement.Quantity · ISO 22400 POQ
生产数量produced_quantitytotal_production_countISO 22400 PQ
良品数量good_quantitytotal_good_count · good_countISO 22400 GQ
报废数量scrap_quantitytotal_bad_count · bad_count — 含义收窄: 旧字段指全部不良,新字段仅指报废ISO 22400 SQ
返工数量rework_quantity(无 — 新字段)ISO 22400 RQ
计划外良品 / 不良good_quantity_out_of_plan / scrap_quantity_out_of_planout_of_plan_good_count / out_of_plan_bad_count
测量良品 / 不良 (PLC)measured_good_quantity / measured_scrap_quantitymeasured_good_count / measured_bad_count
修正增减good_quantity_delta / scrap_quantity_deltagood_delta / bad_delta
修正输入值entered_good_quantity / entered_scrap_quantityentered_good / entered_bad
检验数量inspected_quantityinspected_count
检验不良合计inspected_scrap_quantityinspected_bad_count
按处置记录不良scrap_quantity / rework_quantityscrap_count / rework_countISO 22400 SQ / RQ

变更的响应:/order, /order/query(include=oee), /order/{id}/oee, /order/{id}/quantity (含修订记录), /defects, /order/performance, /kpi/oee/history, /asset/{id}/status, MCP 工作指令工具, 生产事件 OEE_CALCULATED。

  • /asset/{id}/status 的 planned_quantity·good_quantity·scrap_quantity 将显示为进行中工作指令的单位。若无进行中的工作指令,则为 null。
  • 比例字段 (total_good_rate, production_rate, 可用性·性能·质量·OEE) 为无量纲,因此直接使用数值。
  • /asset/{id}/status 中同样包含 rework_quantity (进行中工作指令的返工)。
  • PLC 计数记录 (GET /api/v5/kpi/oee/count 的 good_quantity·scrap_quantity) 和 MCP get_asset_kpi 的按原因报废 (scrap_quantity) 同样采用该时刻工作指令单位的 Quantity。由于计数器为整数计数,因此 计数 1 = 工作指令单位 1 — 若在 kg 单位工作指令中连接整数计数器,则仅按 1 kg 单位计数。小数业绩应通过数量修正或业绩输入,而非计数器。

报废与返工 — «不良» 为两者之和​

按照 ISO 22400 将不良分为报废 (SQ) 与返工 (RQ)。

  • 不良 = 报废 + 返工, 生产 = 良品 + 报废 + 返工 (produced_quantity = good_quantity + scrap_quantity + rework_quantity)。
  • scrap_quantity 仅限报废。由于 PLC 计数的不良未知其处置方式,故计为报废。返工仅在处置方式为 REWORK 的不良记录中产生。
  • 质量 Q 为 良品 ÷ 生产,因此返工也会降低质量 — 仅为分类记录,不影响 OEE 值。
  • 界面通过文字维持此区分:仅指报废的区域(生产历史列、数量修正栏)标注为 «报废»,显示合计的区域标注为 «不良»,若存在返工则附加详情,如 «14 kg (报废 12.75 · 返工 1.25)» — 生产管理 — 数量与单位。
  • 若联动需要 «不良合计»,请将 scrap_quantity + rework_quantity 在相同单位下以 10 进制相加。请勿将单个 scrap_quantity 视为不良合计。

字段数量承载 — 计数器表​

来源 (存储)V5 字段 / 事件字段承载数量
PLC 计数器原账 tm_kpi_oee_count/kpi/oee/count 的 good_quantity · scrap_quantityPLC 计数的良品·不良增量。由于未知处置方式,不良计为报废 (SQ)
工作指令 OEE 行 mm_order_oee.total_production_countproduced_quantity · 事件 pq/pq_quantity生产 (PQ) = 良品 + 报废 + 返工
mm_order_oee.total_good_countgood_quantity · gq/gq_quantity良品 (GQ)
mm_order_oee.total_bad_count − total_rework_countscrap_quantity · sq/sq_quantity报废 (SQ)。total_bad_count 本身 (不良合) 不在传输线路中
mm_order_oee.total_rework_countrework_quantity · rq/rq_quantity返工 (RQ)
mm_order_oee.out_of_plan_good_count / out_of_plan_bad_countgood_quantity_out_of_plan / scrap_quantity_out_of_plan · gq_out_of_plan/sq_out_of_plan(+_quantity)计划停机期间产生的量 — 包含在上述良品·报废中,但在效率计算中剔除
数量修正 mm_order_quantity_correction/order/{id}/quantity 的 measured_*_quantity · good_quantity_delta/scrap_quantity_delta · (历史) entered_*_quantityPLC 测量值, 修正增减, REPLACE 输入值。报废栏仅限报废
不良记录 mm_defect_record (处置 SCRAP/REWORK)/defects 的 quantity·inspected_quantity, 业绩文档 defects.scrap_quantity / rework_quantity / inspected_scrap_quantity按处置的报废·返工, 检验不良合计 (SCRAP + REWORK)
mm_order.planned_quantityplanned_quantity · 事件 planned_quantity计划 (POQ)

请求规则与拒绝​

在业绩·修正·不良记录中填写的数量必须与工作指令 planned_quantity 的单位一致。服务器不进行换算,直接拒绝。 值·单位拒绝属于 422 E1002 (非 400),响应 (application/problem+json) 的 code 为 E1002, reason 字段为下列原因代码。detail 是调用者语言的句子,因此请使用 reason 进行分支判断。

原因代码触发场景
quantity.unit_mismatch发送了与工作指令单位不同的单位
quantity.not_integer在计数单位 (EA·H87·C62·BX·SET) 中发送了小数
quantity.unit_invalid单位缺失或在允许列表 13 个单位之外
quantity.formatquantity_string 不是 10 进制表示字符串 (如指数表示·前导 0·+ 符号·数字类型),或 data_type 与单位不符
quantity.scale小数点第五位及以上
quantity.negative负数 (仅修正增减栏接受负数)
quantity.range绝对值 ≥ 10^14 — 超出存储 numeric(18,4) 范围
  • 若在数量栏提供非对象的值 (如数字 500 等) 或输入 quantity_string·data_type·unit_of_measure 之外的键,则返回 400 E1000 (格式错误)。
  • 工作指令的计划数量必须大于 0。

期间 KPI — 单位混合时不合计​

像 /kpi/period·/kpi/daily 这样合并多个工作指令的响应,仅在单位统一时计算合计。

数量合计栏位于 /kpi/period 的 oee 对象内 good_count·total_count·in_plan_count, 以及 /kpi/daily 的 good_count·bad_count·planned_count。 /kpi/daily 的 bad_count 为 生产 − 良品,即不良合 (报废 + 返工)。

  • 单位统一 — 数量合计栏像目前一样为数字,并附带其单位 unit_of_measure。
  • 单位混合 — 数量合计栏与 unit_of_measure 为 null,改为在 quantities_by_unit 中按单位列出良品·生产数量 (Quantity)。
{
"good_count": null,
"total_count": null,
"in_plan_count": null,
"unit_of_measure": null,
"quantities_by_unit": [
{ "unit_of_measure": "EA",
"good_quantity": { "quantity_string": "2671", "data_type": "integer", "unit_of_measure": "EA" },
"produced_quantity": { "quantity_string": "2700", "data_type": "integer", "unit_of_measure": "EA" } },
{ "unit_of_measure": "KGM",
"good_quantity": { "quantity_string": "1250.5", "data_type": "decimal", "unit_of_measure": "KGM" },
"produced_quantity": { "quantity_string": "1302", "data_type": "decimal", "unit_of_measure": "KGM" } }
]
}

比例 (可用性·性能·质量·OEE) 为无量纲,即使单位混合也直接显示。

EMS 单位值 — 分母单位​

energy_per_unit_kwh·co2_per_unit_kg 的分母为工作指令的良品数量,因此响应中将一同显示该单位 unit_of_measure (/order/{id}/ems, /order/ems/*, /order/query?include=ems)。界面标注为 «kWh/EA», «kWh/kg» 等。 在合并多个工作指令的汇总中,若单位混合,则单位值与单位均返回 null。

事件​

事件架构仅允许«向末尾追加」,因此在不改变类型的情况下增加了字段。

事件数量栏
plantpulse.order.*planned_quantity (number) + planned_quantity_unit_of_measure (Rec 20 代码)
plantpulse.kpi.oee.finalized正本为 gq_quantity·sq_quantity·rq_quantity·pq_quantity·gq_out_of_plan_quantity·sq_out_of_plan_quantity (number) + unit_of_measure。sq 仅限报废,返工在 rq (pq = gq + sq + rq)。整数栏 gq·sq·rq·pq·… 仅在计数单位时承载,小数单位则不存在 — 将在下一个 major 版本中移除
生产事件 OEE_CALCULATEDgood_quantity·scrap_quantity (仅报废)·rework_quantity = Quantity 对象

11.6 MES 联动 — 业绩馈送与 B2MML 对应​

外部工作指令识别 — (external_system, external_id) 配对​

客户系统 (MES·ERP) 的工作指令通过发布系统名称及其在该系统中的编号这两项的配对进行识别 — 形式与员工·维修订单的外部识别一致。

  • 配对在入口和出口路径中均同步存在。V5 POST·PUT·PATCH /api/v5/order 接收 external_system (50 字)·external_id (100 字), 且 GET /order/{id}·列表·/order/query·业绩文档始终承载该配对 (若无则为 null)。控制台表单中无 external_system 栏,请通过 V5 输入。
  • 空值或仅含空格的值存储为 null。超出长度或包含控制字符时返回 422 order.external_ref.invalid。
  • 当两项均非空时,配对具有唯一性。若将相同配对赋予第二个工作指令,返回 409 order.external.duplicate。
  • PUT 将替换整个请求栏 — 缺失的 external_system·external_id 将被删除。若仅修改部分,请使用 PATCH。
  • 目前仍接收仅有 external_id 而无 external_system 的工作指令,但由于不构成配对,无法通过下述 «配对查找» 找到。
  • 事件同样承载配对:plantpulse.order.* (架构 major 2) 的 created·updated·startedaborted 承载 external_id·external_system,迁移事件 (startedaborted) 承载 customer_po_id。
  • 通过配对读取单个工作指令请使用 GET /api/v5/order/by-external/{system}/{external_id} — 若不存在返回 404,若其中一项为空返回 422 order.external_ref.invalid。 /order/query 的过滤器为 external_id + external_system。发送旧参数 external_order_id 时将不予忽略,直接以 422 拒绝。

业绩馈送路径​

HTTP路径行为
GET/api/v5/order/performance业绩馈送 — cursor·site_id·limit。业绩发生变更的工作指令其 performance_revision 递增,并再次出现在末尾
GET/api/v5/order/{order_id}/performance单个工作指令的业绩文档
GET/api/v5/order/performance/by-external/{external_system}/{external_id}配对查找 — 数组 (由于配对唯一,最多一个),若无则为空数组
无旧路径

/api/v5/order/performance/by-external/{external_order_id} (无系统仅编号) 已删除。无兼容路径。

业绩文档的数量键​

位置键 (均为 Quantity)旧键
planplanned_quantitytarget_units
quantitymeasured_good_quantity / measured_scrap_quantitymeasured_good / measured_bad
quantitygood_quantity / scrap_quantitygood / bad
quantity.correctiongood_quantity_delta / scrap_quantity_deltagood_delta / bad_delta
oeegood_quantity / scrap_quantitytotal_good_count / total_bad_count
defectsinspected_scrap_quantity / scrap_quantity / rework_quantityinspected_bad_count / scrap_count / rework_count

quantity.correction_version, progress.expected_now_units·pace_units 的名称保持不变 (小数单位为小数数值)。

quantity.scrap_quantity 仅限报废 (PLC 不良 + SCRAP 记录),与 defects.scrap_quantity 含义相同。quantity.rework_quantity 与 defects.rework_quantity 的值相同。defects.inspected_scrap_quantity 为检验不良合计 (SCRAP + REWORK)。

业绩文档状态 — 如何读取变更内容​

单个业绩文档包含工作指令的当前状态,状态变更时版本号递增。

字段含义
actual.status存储状态 WAIT·START·PAUSED·END·ABORTED — 11.1。取消为 ABORTED + actual.abort_code=CANCELLED
actual.isa95_stateISA-95 工作指令状态 Ready·Running·Held·Completed·Aborted
performance_revision业绩变更次数。每次变更递增 1,馈送将该工作指令重新置于末尾。0 为尚未结束的工作指令 — 不在馈送中,仅通过 /order/{id}/performance 读取
quantity.correction_version数量修正版本。无修正时为测量值,每次修正递增 — 历史记录见 /order/{id}/quantity 的修订记录
changed_at · change_cause最近变更时间及其原因 — ENDED·QUANTITY (数量修正)·STOP_REASON·OEE_FINAL·DEFECT (不良记录)·PROGRESS·BASELINE

数量仅以 «值 + 单位» 承载,未计算的字段为 null 而非 0。MES 仅需用一个更新的 order_id 的 performance_revision 文档整体替换前一文档即可。

B2MML 对应表​

单个业绩文档对应 ISA-95 Part 4 的 Job Response (Segment Response),其数量对应 Material Actual (Produced) 的 Quantity。

ISA-95 / B2MMLPlantPulse V5备注
QuantityValueType — QuantityString · DataType · UnitOfMeasureQuantity — quantity_string · data_type · unit_of_measure1:1。不使用 B2MML 的可选字段 Key
UnitOfMeasure 值UN/ECE Rec 20 代码允许列表见 11.5
Job Order 的 IDexternal_id发布系统名称为 external_system — 二者为配对
Job Order · MaterialRequirement 的 Quantityplanned_quantityISO 22400 POQ
Job Order 的名称order_name
Job Order 的 StartTime · EndTimeplanned_start_timestamp · planned_end_timestamp计划时间。实际时间为 actual_start_timestamp · actual_end_timestamp
Job Response单个业绩文档 (/order/{id}/performance)
MaterialActual(Produced) 的 Quantityproduced_quantityISO 22400 PQ
其中良品good_quantityISO 22400 GQ
其中报废scrap_quantityISO 22400 SQ
其中返工defects.rework_quantityISO 22400 RQ

11.7 应用场景​

场景 — MES 联动工作指令自动创建​

import java.text.SimpleDateFormat;
import java.util.Date;

SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
String today = df.format(new Date());

// 외부 MES 큐에서 받은 주문을 V5 Order로 변환
for (MesOrder mes : mesQueue) {
OrderRequestV5 req = new OrderRequestV5();
req.setOrder_id("ORDER_" + today + "_" + String.format("%03d", mes.seq));
req.setSite_id("SITE_DJ");
req.setAsset_id(mes.equipId);
req.setProduct_id(mes.productId);
// MES 수량을 그대로 — 단위 환산은 하지 않는다. 단위는 허용 목록(11.5) 안의 Rec 20 코드여야 한다
req.setPlanned_quantity(Quantity.of(mes.qty.toPlainString(), mes.unitCode));
req.setExternal_id(mes.mesOrderId);
req.setExternal_system("MES");
req.setPlanned_start_timestamp(mes.plannedStart);
req.setPlanned_end_timestamp(mes.plannedEnd);
client.order().create(req);
}

场景 — 安全状态迁移辅助工具​

public static boolean safeStart(APIClient_V5 client, String orderId) {
OrderResponseV5 o = client.order().get(orderId);
if (o == null) {
log.warn("작업지시 없음: " + orderId);
return false;
}
if (!"WAIT".equals(o.getStatus())) {
log.warn("WAIT 상태가 아님: " + o.getStatus());
return false;
}
return client.order().start(orderId);
}

下一步​