12. Order Service
Access via client.order(). It manages the entire lifecycle of a Work Order—creation → start → stop/resume → end—using an ISA-88 based state machine.
11.1 Work Order Status (ISA-88 Based)
CREATE → WAIT ──start()──► START ──pause()──► PAUSED
│ │
│ resume()
│ │
▼ ▼
END ◄──end()──── START
│
└─ (또는) ──abort()──► ABORTED
Status (status) | Meaning | Transition Method | ISA-95 Status (isa95_state) |
|---|---|---|---|
WAIT | Waiting (Initial state after creation) | create() result | Ready |
START | In Progress | start(), resume() | Running |
PAUSED | Paused | pause() | Held |
END | Normal Completion | end() | Completed |
ABORTED | Abnormal Termination | abort() | Aborted |
status is stored exactly as the value and consists of only these five. A work order canceled without starting is not a new state, but ABORTED + abort_code=CANCELLED. Work order rows (/order·List·/order/query), performance documents, and plantpulse.order.* events append the ISA-95 Part 4 work order status isa95_state—the mapping is the single table above, and all paths yield the same value.
For calls where state transition is impossible (e.g., calling
start()again while already inSTARTstate), the server sends an OK +data.success=falseresponse, and the V5 method returnsfalse.
11.2 Method List
CRUD
| Method | Return Type | HTTP | Endpoint |
|---|---|---|---|
create(OrderRequestV5) | OrderResponseV5 or null | POST | /api/v5/order |
update(order_id, OrderRequestV5) | OrderResponseV5 or null | PUT | /api/v5/order/{id} |
delete(order_id) | boolean | DELETE | /api/v5/order/{id} |
get(order_id) | OrderResponseV5 or null | GET | /api/v5/order/{id} |
list() | List<OrderResponseV5> | GET | /api/v5/order |
exists(order_id) | boolean | GET | /api/v5/order/{id}/exists |
Lifecycle (All return boolean)
| Method | HTTP | Endpoint |
|---|---|---|
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
| Field | Type | Description |
|---|---|---|
order_id | String | Work Order ID (PK) |
order_name | String | Work Order Name — Required, cannot be empty (422 order.name.required). Name of B2MML JobOrder |
description | String | Description |
site_id | String | Affiliated Site |
asset_id | String | Target equipment |
customer_id | String | Customer (Optional) |
product_id | String | Product to produce |
employee_id | String | Assigned employee (Optional) |
planned_quantity | Quantity | Planned quantity — ISA-95 / B2MML QuantityValueType. See 11.5 Quantity below |
time_per_unit_in_ms | long | Standard time per unit |
planned_start_timestamp | long | Planned start time (milliseconds) |
planned_end_timestamp | long | Planned end time (milliseconds) |
external_id | String | Work order number of external system (MES/ERP) (up to 100 chars). Identified as a pair with external_system — 11.6 |
external_system | String | Name of the external system that issued the work order (up to 50 chars) — other half of the external identification pair |
customer_po_id | String | Customer Purchase Order (PO) number corresponding to this work order (Optional) |
status | String | (Response only) Current status — stored values WAIT·START·PAUSED·END·ABORTED |
isa95_state | String | (Response only) ISA-95 work order status — Ready·Running·Held·Completed·Aborted (11.1) |
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. Old names are not read in requests and do not appear in responses —
Upgrade Notes.
11.4 Usage Examples
Work Order Creation
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);
Standard Lifecycle
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);
Abnormal Termination
// abort 는 별도 인자 없이 호출. 상세 사유는 update() 로 description/notes 에 기록.
if (!client.order().abort("ORDER_000001")) {
System.err.println("중단 실패");
}
Single Inquiry / Existence Check
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");
Full List
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());
}
In-Progress Work Orders Only (Client-side filter)
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());
Work Orders by equipment
String assetId = "ASSET_DJ_M_0001";
List<OrderResponseV5> assetOrders = client.order().list().stream()
.filter(o -> assetId.equals(o.getAsset_id()))
.collect(Collectors.toList());
Statistics by Status
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));
Modification / Deletion
// 수정 (계획 시간 연장)
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 Quantity — ISA-95 Quantity
The quantity of a work order (planned, production, good, scrap, rework ...) is not a single number, but an object containing both value and unit.
The format is 1:1 with QuantityValueType of ISA-95 (IEC 62264) / B2MML V0700.
Based on V5 API (OpenAPI info.version 5.0) · Quantity agreement 2026-10-30 · Name wave 2026-10-31 · Platform 2026.11 version (server-web 974891b4).
Events are based on plantpulse.order.*·plantpulse.calendar.* schema major 2, plantpulse.kpi.oee.finalized major 1, DB is based on Flyway V99·V100·V103 and core migration V12V16·V21V23 —
Upgrade Notes.
[
{ "quantity_string": "1250.5", "data_type": "decimal", "unit_of_measure": "KGM" },
{ "quantity_string": "1200", "data_type": "integer", "unit_of_measure": "EA" }
]
| Field | B2MML | Type | Rule |
|---|---|---|---|
quantity_string | QuantityString | string | Decimal notation exactly — exponential notation forbidden, decimal point is ., up to four decimal places. Counting units must be integers |
data_type | DataType | string | integer (Counting unit) or decimal (Others). Determined by the server from the unit — can be omitted in requests, but must match the unit if provided |
unit_of_measure | UnitOfMeasure | string | UN/ECE Recommendation 20 common code — allowed list below |
Because B2MML defines it as QuantityString and most JSON parsers read numbers as double, losing decimal accuracy. In the SDK, read as Quantity.toBigDecimal() for calculations. When creating a request, use Quantity.of("1250.5", "KGM") — if data_type is left empty, the server fills it.
Units — Allowed List (UN/ECE Rec 20)
| Code | Meaning | data_type | Screen Symbol |
|---|---|---|---|
EA | each — Number of individual items | integer | EA |
H87 | piece | integer | pc |
C62 | one (unit) | integer | unit |
BX | box — Number of boxes | integer | box |
SET | set — Number of sets/kits | integer | set |
KGM | kilogram | decimal | kg |
GRM | gram | decimal | g |
TNE | tonne | decimal | t |
LTR | litre | decimal | L |
MLT | millilitre | decimal | mL |
MTQ | cubic metre | decimal | m³ |
MTR | metre | decimal | m |
MTK | square metre | decimal | m² |
- There are 13 allowed units, and the counting units are
EA·H87·C62·BX·SET. Codes outside the list are rejected (quantity.unit_invalid). Codes are compared exactly, including case —ea,KG,PCSare not allowed codes. - If a code not in the screen symbols is received (e.g., old data), it is displayed exactly as the code.
- No unit conversion is performed (unit master and conversion are the responsibility of the MES). Quantities with different units are not added together.
- Screen symbols are independent of language — on Korean screens, «개» is not used, but
EA. Symbols are always attached (including count).
Field Names — ISO 22400
Field names follow the terminology of ISA-95 and ISO 22400-2 (KPI pair of IEC 62264). Old names no longer appear in responses (no compatibility fields).
| Meaning | Field (Quantity) | Old Field | Basis |
|---|---|---|---|
| Planned quantity | planned_quantity | target_units + unit | ISA-95 MaterialRequirement.Quantity · ISO 22400 POQ |
| Production quantity | produced_quantity | total_production_count | ISO 22400 PQ |
| Good quantity | good_quantity | total_good_count · good_count | ISO 22400 GQ |
| Scrap quantity | scrap_quantity | total_bad_count · bad_count — Meaning narrowed: old field was total defect, new field is scrap only | ISO 22400 SQ |
| Rework quantity | rework_quantity | (None — new field) | ISO 22400 RQ |
| Off-plan good / defect | good_quantity_out_of_plan / scrap_quantity_out_of_plan | out_of_plan_good_count / out_of_plan_bad_count | |
| Measured good / defect (PLC) | measured_good_quantity / measured_scrap_quantity | measured_good_count / measured_bad_count | |
| Calibration increase/decrease | good_quantity_delta / scrap_quantity_delta | good_delta / bad_delta | |
| Calibration input value | entered_good_quantity / entered_scrap_quantity | entered_good / entered_bad | |
| Inspection quantity | inspected_quantity | inspected_count | |
| Inspection defect total | inspected_scrap_quantity | inspected_bad_count | |
| Defect record by disposition | scrap_quantity / rework_quantity | scrap_count / rework_count | ISO 22400 SQ / RQ |
Changing responses: /order, /order/query(include=oee), /order/{id}/oee, /order/{id}/quantity(including revision history),
/defects, /order/performance, /kpi/oee/history, /asset/{id}/status, MCP work order tool, production event OEE_CALCULATED.
/asset/{id}/status'splanned_quantity·good_quantity·scrap_quantityappear as the unit of the in-progress work order. If there is no in-progress work order, it is null.- Ratio fields (
total_good_rate,production_rate, availability, performance, quality, OEE) are dimensionless and thus remain as numbers. /asset/{id}/statusalso hasrework_quantity(rework of the in-progress work order).- PLC counter records (
GET /api/v5/kpi/oee/count'sgood_quantity·scrap_quantity) and cause-based scrap in MCPget_asset_kpi(scrap_quantity) are also the Quantity of the work order unit at that time. Since counters count integers, count 1 = work order unit 1 — if an integer counter is attached to a kg work order, it counts in 1 kg units. Decimal performance is entered via quantity correction or performance input, not the counter.
Scrap and Rework — «Defect» is the sum of the two
Defects are divided into scrap (SQ) and rework (RQ) according to ISO 22400.
- Defect = Scrap + Rework, Production = Good + Scrap + Rework(
produced_quantity=good_quantity+scrap_quantity+rework_quantity). scrap_quantityis scrap only. Defects counted by PLC are treated as scrap as the disposition is unknown. Rework only occurs in defect records where the disposition isREWORK.- Since Quality Q is Good ÷ Production, rework also reduces quality — it is simply recorded separately and does not change the OEE value.
- The screen maintains this distinction verbally: areas referring only to scrap (production history column, quantity correction field) are labeled «Scrap», while areas showing the total are labeled «Defect». If rework exists, the detail is appended as «14 kg (Scrap 12.75 · Rework 1.25)» — Production Management — Quantity and Units.
- If integration requires «Defect Total», add
scrap_quantity+rework_quantityas decimals of the same unit. Do not readscrap_quantityas the defect total.
Which field carries which quantity — Counter Table
| Source (Stored) | V5 Field / Event Field | Quantity Carried |
|---|---|---|
PLC counter ledger tm_kpi_oee_count | /kpi/oee/count's good_quantity · scrap_quantity | Good/Defect increments counted by PLC. Defect is scrap (SQ) since disposition is unknown |
Work order OEE row mm_order_oee.total_production_count | produced_quantity · Event pq/pq_quantity | Production(PQ) = Good + Scrap + Rework |
mm_order_oee.total_good_count | good_quantity · gq/gq_quantity | Good(GQ) |
mm_order_oee.total_bad_count − total_rework_count | scrap_quantity · sq/sq_quantity | Scrap(SQ). total_bad_count itself (defect total) is not sent over the wire |
mm_order_oee.total_rework_count | rework_quantity · rq/rq_quantity | Rework(RQ) |
mm_order_oee.out_of_plan_good_count / out_of_plan_bad_count | good_quantity_out_of_plan / scrap_quantity_out_of_plan · gq_out_of_plan/sq_out_of_plan(+_quantity) | Volume produced during planned stop — included in above good/scrap, but subtracted in efficiency calculation |
Quantity correction mm_order_quantity_correction | /order/{id}/quantity's measured_*_quantity · good_quantity_delta/scrap_quantity_delta · (History) entered_*_quantity | PLC measured value, correction increase/decrease, REPLACE input value. Scrap field is scrap only |
Defect record mm_defect_record (Disposition SCRAP/REWORK) | /defects's quantity·inspected_quantity, Performance document defects.scrap_quantity / rework_quantity / inspected_scrap_quantity | Scrap/Rework by disposition, inspection defect total(SCRAP + REWORK) |
mm_order.planned_quantity | planned_quantity · Event planned_quantity | Planned(POQ) |
Request Rules and Rejections
The quantity carried in performance, calibration, or defect records must be in the same unit as work order planned_quantity. The server rejects it without conversion.
Value/unit rejections are 422 E1002 (not 400), and in the response (application/problem+json), code is E1002, and the reason field contains the reason code below. Since detail is a sentence in the caller's language, use reason for branching.
| Reason Code | When |
|---|---|
quantity.unit_mismatch | Unit different from the work order unit was sent |
quantity.not_integer | Decimal sent for a counting unit(EA·H87·C62·BX·SET) |
quantity.unit_invalid | Unit is missing or outside the allowed list of 13 |
quantity.format | quantity_string is not a decimal notation string (exponential notation, leading zero, + sign, numeric type), or data_type does not match the unit |
quantity.scale | Fifth decimal place or more |
quantity.negative | Negative number (only calibration increase/decrease fields accept negatives) |
quantity.range | Absolute value is 1014 or more — outside the range of stored numeric(18,4) |
- Providing a value (such as number
500) instead of an object in the quantity field or using keys outsidequantity_string·data_type·unit_of_measureresults in 400E1000(format error). - The planned quantity of the work order must be greater than 0.
Period KPI — Do not sum if units are mixed
Responses that aggregate multiple work orders, such as /kpi/period·/kpi/daily, only calculate totals when there is a single unit.
Quantity total fields are good_count·total_count·in_plan_count inside the oee object of /kpi/period, and good_count·bad_count·planned_count of /kpi/daily.
bad_count of /kpi/daily is Production − Good, which is the Defect Total (Scrap + Rework).
- Single unit — Quantity total fields are numbers as they are, with the unit
unit_of_measureattached. - Mixed units — Quantity total fields and
unit_of_measureare null; instead, good/production quantities per unit are listed as Quantity inquantities_by_unit.
{
"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" } }
]
}
Ratios (availability, performance, quality, OEE) are dimensionless, so they are displayed as is even if units are mixed.
EMS Value per Unit — Unit of Denominator
The denominator of energy_per_unit_kwh·co2_per_unit_kg is the good quantity of the work order, so that unit unit_of_measure appears in the response
(/order/{id}/ems, /order/ems/*, /order/query?include=ems). The screen displays it as «kWh/EA», «kWh/kg».
In aggregations of multiple work orders, if units are mixed, the value per unit and the unit are null.
Events
Since event schemas only allow «appending to the end», fields were added without changing types.
| Event | Quantity Field |
|---|---|
plantpulse.order.* | planned_quantity(number) + planned_quantity_unit_of_measure(Rec 20 code) |
plantpulse.kpi.oee.finalized | The original is gq_quantity·sq_quantity·rq_quantity·pq_quantity·gq_out_of_plan_quantity·sq_out_of_plan_quantity(number) + unit_of_measure. sq is scrap only, rework is rq(pq = gq + sq + rq). Integer fields gq·sq·rq·pq·… are only filled for counting units and are absent for decimal units — will be removed in the next major version |
Production event OEE_CALCULATED | good_quantity·scrap_quantity(scrap only)·rework_quantity = Quantity object |
11.6 MES Integration — Performance Feed and B2MML Mapping
External Work Order Identification — (external_system, external_id) Pair
Work orders from customer systems (MES/ERP) are identified by a pair of two fields: the issuing system name and the number within that system — same as the external identification for employee or maintenance orders.
- The pair is present both on the incoming and outgoing paths. V5
POST·PUT·PATCH /api/v5/orderreceiveexternal_system(50 chars)·external_id(100 chars), andGET /order/{id}·List·/order/query·performance documents always carry both (null if absent). Since the console form does not haveexternal_systemfields, enter them via V5. - Values that are empty or whitespace only are stored as null. If the length is exceeded or control characters are present, it is 422
order.external_ref.invalid. - The pair is unique when both fields are not empty. Assigning the same pair to a second work order results in 409
order.external.duplicate. PUTreplaces the entire request field — missingexternal_system·external_idare deleted. To change only a part, usePATCH.- Work orders with
external_idbut noexternal_systemare still accepted, but since they are not a pair, they cannot be found using the «Find by Pair» method below. - Events also carry the pair:
created·updated·startedabortedofplantpulse.order.*(schema major 2) carryexternal_id·external_system, and transition events (startedaborted) also carrycustomer_po_id. - To read a single work order by pair, use
GET /api/v5/order/by-external/{system}/{external_id}— 404 if not found, 422order.external_ref.invalidif one side is empty. The filter for/order/queryis alsoexternal_id+external_system. Sending the old parameterexternal_order_idis not ignored but rejected as 422.
Performance Feed Path
| HTTP | Path | Action |
|---|---|---|
| GET | /api/v5/order/performance | Performance feed — cursor·site_id·limit. Work orders with changed performance have performance_revision incremented by one and appear again at the end |
| GET | /api/v5/order/{order_id}/performance | Performance document of a single work order |
| GET | /api/v5/order/performance/by-external/{external_system}/{external_id} | Find by pair — array (at most one since pair is unique), empty array if not found |
/api/v5/order/performance/by-external/{external_order_id} (number only without system) has been removed. There are no compatibility paths.
Quantity Keys in Performance Document
| Location | Key (All Quantity) | Old Key |
|---|---|---|
plan | planned_quantity | target_units |
quantity | measured_good_quantity / measured_scrap_quantity | measured_good / measured_bad |
quantity | good_quantity / scrap_quantity | good / bad |
quantity.correction | good_quantity_delta / scrap_quantity_delta | good_delta / bad_delta |
oee | good_quantity / scrap_quantity | total_good_count / total_bad_count |
defects | inspected_scrap_quantity / scrap_quantity / rework_quantity | inspected_bad_count / scrap_count / rework_count |
quantity.correction_version, progress.expected_now_units·pace_units names remain the same (decimal number if decimal unit).
quantity.scrap_quantity is scrap only (PLC defect + SCRAP record) and has the same meaning as defects.scrap_quantity. quantity.rework_quantity has the same value as defects.rework_quantity. defects.inspected_scrap_quantity is the total inspection defect(SCRAP + REWORK).
Status of Performance Document — How to read what changed
A single performance document contains the current status of one work order, and the version increases whenever the status changes.
| Field | Meaning |
|---|---|
actual.status | Stored status WAIT·START·PAUSED·END·ABORTED — 11.1. Cancellation is ABORTED + actual.abort_code=CANCELLED |
actual.isa95_state | ISA-95 work order status Ready·Running·Held·Completed·Aborted |
performance_revision | Number of times performance has changed. Increases by 1 each time, and the feed places that work order at the end. 0 is a work order not yet finished — not in the feed and only read via /order/{id}/performance |
quantity.correction_version | Quantity correction version. If no correction, it is the measured value; increases per correction — history is in the revision history of /order/{id}/quantity |
changed_at · change_cause | Time and cause of last change — ENDED·QUANTITY(quantity correction)·STOP_REASON·OEE_FINAL·DEFECT(defect record)·PROGRESS·BASELINE |
Quantities are carried only as «value + unit», and fields that are not calculated are null rather than 0. The MES can replace the entire previous document with a newer document where the same order_id's performance_revision is larger.
B2MML Mapping Table
A single performance document corresponds to the Job Response (Segment Response) of ISA-95 Part 4, and its quantity corresponds to the Quantity of Material Actual (Produced).
| ISA-95 / B2MML | PlantPulse V5 | Note |
|---|---|---|
QuantityValueType — QuantityString · DataType · UnitOfMeasure | Quantity — quantity_string · data_type · unit_of_measure | 1:1. Optional B2MML field Key is not used |
UnitOfMeasure Value | UN/ECE Rec 20 Code | Allowed list is in 11.5 |
| Job Order ID | external_id | Issuing system name is external_system — the two are a pair |
| Job Order · MaterialRequirement Quantity | planned_quantity | ISO 22400 POQ |
| Job Order Name | order_name | |
| Job Order StartTime · EndTime | planned_start_timestamp · planned_end_timestamp | Planned time. Actual time is actual_start_timestamp · actual_end_timestamp |
| Job Response | Single performance document (/order/{id}/performance) | |
| MaterialActual(Produced) Quantity | produced_quantity | ISO 22400 PQ |
| Good portion among those | good_quantity | ISO 22400 GQ |
| Scrap portion among those | scrap_quantity | ISO 22400 SQ |
| Rework portion among those | defects.rework_quantity | ISO 22400 RQ |
11.7 Application Scenarios
Scenario — Automatic Work Order Creation via MES Integration
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);
}
Scenario — Safe State Transition Helper
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);
}
Next Steps
- Customer Service, Employee Service, Product Service — Master data attached to Orders
- Calendar Service — Conflict check between work orders and inspection schedules
- Upgrade Notes — What integrations must fix during Quantity transition