@operato/ops-contract 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contract.d.ts +35 -12
- package/dist/erp.d.ts +7 -12
- package/dist/erp.js +6 -6
- package/dist-cjs/index.cjs +5 -5
- package/package.json +1 -1
package/dist/contract.d.ts
CHANGED
|
@@ -1798,12 +1798,7 @@ export interface TaskState {
|
|
|
1798
1798
|
* **실제로 들어가고 나온 자재** — ISA-95 `JobResponse.MaterialActual`(`OpMaterialActualType`).
|
|
1799
1799
|
* 명세(계획)가 아니라 일어난 일이다. 투입 인원·설비와 같은 채널에 실어 실적을 한 곳에서 읽는다.
|
|
1800
1800
|
*/
|
|
1801
|
-
materialActual?:
|
|
1802
|
-
definitionId: string;
|
|
1803
|
-
use: 'consumed' | 'produced';
|
|
1804
|
-
quantity: number;
|
|
1805
|
-
uom?: string;
|
|
1806
|
-
}[];
|
|
1801
|
+
materialActual?: MaterialActual[];
|
|
1807
1802
|
}
|
|
1808
1803
|
/**
|
|
1809
1804
|
* 오더 하나의 관측 상태 — **ISA-95 `OperationsRequest`**(Part 4, 일정).
|
|
@@ -3102,6 +3097,39 @@ export interface QualityDelta {
|
|
|
3102
3097
|
*/
|
|
3103
3098
|
taskId?: string;
|
|
3104
3099
|
}
|
|
3100
|
+
/**
|
|
3101
|
+
* 실제로 들어가고 나온 자재 한 줄 — ISA-95 `OpMaterialActualType` 의 부분집합.
|
|
3102
|
+
*
|
|
3103
|
+
* ── 왜 이름 있는 타입인가 (2026-08-31) ────────────────────────────────────
|
|
3104
|
+
* 같은 데이터가 네 곳에 각각 인라인으로 적혀 있었다(작업 상태 둘 · 커널 · ERP). ERP 쪽은 필드명까지
|
|
3105
|
+
* 달랐다(`materialDefinitionId` · `direction`). 같은 데이터를 여러 이름으로 부르면 옮기는 코드가
|
|
3106
|
+
* 생기고, 그 코드가 언젠가 어긋난다.
|
|
3107
|
+
*
|
|
3108
|
+
* 표준 매핑은 커널이 이미 적어 두었다 — `MaterialDefinitionID` → `definitionId`,
|
|
3109
|
+
* `MaterialUse` → `use`. 그 이름을 그대로 쓴다.
|
|
3110
|
+
*/
|
|
3111
|
+
export interface MaterialActual {
|
|
3112
|
+
/** 표준 `MaterialDefinitionID`. */
|
|
3113
|
+
definitionId: string;
|
|
3114
|
+
/** 표준 `MaterialUse`. */
|
|
3115
|
+
use: 'consumed' | 'produced';
|
|
3116
|
+
quantity: number;
|
|
3117
|
+
uom?: string;
|
|
3118
|
+
/**
|
|
3119
|
+
* 어느 로트를 썼는가 — 표준 `MaterialLotID`.
|
|
3120
|
+
*
|
|
3121
|
+
* ── 값은 식별자다 (2026-08-31, MES 레인 요청) ─────────────────────────────
|
|
3122
|
+
* 로트 번호 문자열이 아니라 **식별자**를 넣는다. GS1 로 식별되는 로트는
|
|
3123
|
+
* `urn:epc:class:lgtin:<프리픽스>.<품번>.<로트>` 이고, 그렇지 않으면 원본 시스템의 로트 식별자다.
|
|
3124
|
+
*
|
|
3125
|
+
* 문자열을 기준값으로 두면 이것을 쓰는 네 곳에서 각각 식별자를 다시 조립해야 한다 — 불합격 로트의
|
|
3126
|
+
* 이동 제한, EPCIS `TransformationEvent` 의 입력·출력 목록, 현장 자재 스캔, 로트 엔티티. 조립
|
|
3127
|
+
* 규칙이 네 곳에 생기면 그중 하나가 달라지는 날 그 경로에서만 로트가 맞지 않고 오류는 발생하지 않는다.
|
|
3128
|
+
*
|
|
3129
|
+
* 사람이 읽는 로트 번호는 식별자에서 파생한다 — `ItemState.lot` 이 이미 그 방식이다.
|
|
3130
|
+
*/
|
|
3131
|
+
lotId?: string;
|
|
3132
|
+
}
|
|
3105
3133
|
export interface TaskStatusDelta {
|
|
3106
3134
|
taskId: string;
|
|
3107
3135
|
/** 착수 시각(절대 sim-clock) — 보간 앵커. TaskState 와 같은 뜻. */
|
|
@@ -3158,12 +3186,7 @@ export interface TaskStatusDelta {
|
|
|
3158
3186
|
* **실제로 들어가고 나온 자재** — ISA-95 `JobResponse.MaterialActual`(`OpMaterialActualType`).
|
|
3159
3187
|
* 명세(계획)가 아니라 일어난 일이다. 투입 인원·설비와 같은 채널에 실어 실적을 한 곳에서 읽는다.
|
|
3160
3188
|
*/
|
|
3161
|
-
materialActual?:
|
|
3162
|
-
definitionId: string;
|
|
3163
|
-
use: 'consumed' | 'produced';
|
|
3164
|
-
quantity: number;
|
|
3165
|
-
uom?: string;
|
|
3166
|
-
}[];
|
|
3189
|
+
materialActual?: MaterialActual[];
|
|
3167
3190
|
}
|
|
3168
3191
|
export interface EquipmentStatusDelta extends EffectivePeriod {
|
|
3169
3192
|
moverId: string;
|
package/dist/erp.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ISOTime } from './contract.ts';
|
|
1
|
+
import type { ISOTime, MaterialActual } from './contract.ts';
|
|
2
2
|
/**
|
|
3
3
|
* **무엇을 얼마나 만들라** — 이 사실을 나르는 자리가 둘이고, 어휘는 하나다.
|
|
4
4
|
*
|
|
@@ -106,7 +106,12 @@ export interface ProductionPerformanceEntry {
|
|
|
106
106
|
to: ISOTime;
|
|
107
107
|
/** 누가 했나 — ERP 의 인사번호. 「누가 적었나」는 여기 오지 않는다(MES 의 감사 추적이다). */
|
|
108
108
|
personId?: string;
|
|
109
|
-
/**
|
|
109
|
+
/**
|
|
110
|
+
* 쓴 자재 — 소비 문서가 된다. 없으면 자재 소비를 올리지 않는다(0 으로 채우지 않는다).
|
|
111
|
+
*
|
|
112
|
+
* 모양은 커널과 같은 `MaterialActual` 이다. 처음에는 여기에 따로 적었고 필드명이 달랐다
|
|
113
|
+
* (`materialDefinitionId` · `direction`) — 같은 데이터를 두 이름으로 부르면 옮기는 코드가 생긴다.
|
|
114
|
+
*/
|
|
110
115
|
materialActual?: MaterialActual[];
|
|
111
116
|
/**
|
|
112
117
|
* **이것이 이 지시의 마지막 실적인가** — ERP 가 이 값으로 오더를 닫는다.
|
|
@@ -117,16 +122,6 @@ export interface ProductionPerformanceEntry {
|
|
|
117
122
|
final?: boolean;
|
|
118
123
|
recordTime?: ISOTime;
|
|
119
124
|
}
|
|
120
|
-
/** 실제로 들어가고 나온 자재 한 줄. */
|
|
121
|
-
export interface MaterialActual {
|
|
122
|
-
/** 마스터의 `MaterialDefinition` 식별자 — 지시와 같은 이름을 쓴다. */
|
|
123
|
-
materialDefinitionId: string;
|
|
124
|
-
quantity: number;
|
|
125
|
-
uom: string;
|
|
126
|
-
/** `consumed` 소비 · `produced` 산출. 부호로 구별하지 않는다 — 음수는 되돌림과 섞인다. */
|
|
127
|
-
direction: 'consumed' | 'produced';
|
|
128
|
-
lot?: string;
|
|
129
|
-
}
|
|
130
125
|
/**
|
|
131
126
|
* 실적의 **멱등 키** — 같은 실적이 두 번 올라가지 않게.
|
|
132
127
|
*
|
package/dist/erp.js
CHANGED
|
@@ -88,14 +88,14 @@ export function validatePerformance(e, nowMs) {
|
|
|
88
88
|
errors.push('아직 오지 않은 시각까지의 실적이다');
|
|
89
89
|
}
|
|
90
90
|
for (const m of e?.materialActual ?? []) {
|
|
91
|
-
if (!String(m?.
|
|
92
|
-
errors.push('자재 줄에
|
|
91
|
+
if (!String(m?.definitionId ?? '').trim())
|
|
92
|
+
errors.push('자재 줄에 definitionId 가 없다');
|
|
93
93
|
if (!String(m?.uom ?? '').trim())
|
|
94
|
-
errors.push(`${m?.
|
|
94
|
+
errors.push(`${m?.definitionId}: uom 없음 — 단위는 ERP 의 사실이므로 지어내지 않는다`);
|
|
95
95
|
if (typeof m?.quantity !== 'number' || !(m.quantity > 0))
|
|
96
|
-
errors.push(`${m?.
|
|
97
|
-
if (m?.
|
|
98
|
-
errors.push(`${m?.
|
|
96
|
+
errors.push(`${m?.definitionId}: 수량이 0 이하다`);
|
|
97
|
+
if (m?.use !== 'consumed' && m?.use !== 'produced') {
|
|
98
|
+
errors.push(`${m?.definitionId}: use 가 consumed · produced 가 아니다`);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
return errors;
|
package/dist-cjs/index.cjs
CHANGED
|
@@ -3930,11 +3930,11 @@ function validatePerformance(e, nowMs) {
|
|
|
3930
3930
|
if (to > nowMs) errors.push("\uC544\uC9C1 \uC624\uC9C0 \uC54A\uC740 \uC2DC\uAC01\uAE4C\uC9C0\uC758 \uC2E4\uC801\uC774\uB2E4");
|
|
3931
3931
|
}
|
|
3932
3932
|
for (const m of e?.materialActual ?? []) {
|
|
3933
|
-
if (!String(m?.
|
|
3934
|
-
if (!String(m?.uom ?? "").trim()) errors.push(`${m?.
|
|
3935
|
-
if (typeof m?.quantity !== "number" || !(m.quantity > 0)) errors.push(`${m?.
|
|
3936
|
-
if (m?.
|
|
3937
|
-
errors.push(`${m?.
|
|
3933
|
+
if (!String(m?.definitionId ?? "").trim()) errors.push("\uC790\uC7AC \uC904\uC5D0 definitionId \uAC00 \uC5C6\uB2E4");
|
|
3934
|
+
if (!String(m?.uom ?? "").trim()) errors.push(`${m?.definitionId}: uom \uC5C6\uC74C \u2014 \uB2E8\uC704\uB294 ERP \uC758 \uC0AC\uC2E4\uC774\uBBC0\uB85C \uC9C0\uC5B4\uB0B4\uC9C0 \uC54A\uB294\uB2E4`);
|
|
3935
|
+
if (typeof m?.quantity !== "number" || !(m.quantity > 0)) errors.push(`${m?.definitionId}: \uC218\uB7C9\uC774 0 \uC774\uD558\uB2E4`);
|
|
3936
|
+
if (m?.use !== "consumed" && m?.use !== "produced") {
|
|
3937
|
+
errors.push(`${m?.definitionId}: use \uAC00 consumed \xB7 produced \uAC00 \uC544\uB2C8\uB2E4`);
|
|
3938
3938
|
}
|
|
3939
3939
|
}
|
|
3940
3940
|
return errors;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@operato/ops-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Operations domain contract — the standard vocabulary that producers and readers agree on (EPCIS 2.0/GS1, ISA-95, IEC 61850/ISO 50001). Types, guards, validation. No state, no engine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist-cjs/index.cjs",
|