@things-factory/ops-master 10.1.34 → 10.1.36

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.
Files changed (151) hide show
  1. package/dist-client/master-change-approval.d.ts +7 -0
  2. package/dist-client/master-change-approval.js +16 -0
  3. package/dist-client/master-change-approval.js.map +1 -1
  4. package/dist-client/pages/master/applied-when-dialog.d.ts +45 -0
  5. package/dist-client/pages/master/applied-when-dialog.js +139 -0
  6. package/dist-client/pages/master/applied-when-dialog.js.map +1 -0
  7. package/dist-client/pages/master/assignment-fields.d.ts +28 -0
  8. package/dist-client/pages/master/assignment-fields.js +55 -0
  9. package/dist-client/pages/master/assignment-fields.js.map +1 -0
  10. package/dist-client/pages/master/equipment.js +1 -0
  11. package/dist-client/pages/master/equipment.js.map +1 -1
  12. package/dist-client/pages/master/master-page-base.d.ts +14 -0
  13. package/dist-client/pages/master/master-page-base.js +40 -4
  14. package/dist-client/pages/master/master-page-base.js.map +1 -1
  15. package/dist-client/pages/master/material-definition.d.ts +4 -11
  16. package/dist-client/pages/master/material-definition.js +5 -53
  17. package/dist-client/pages/master/material-definition.js.map +1 -1
  18. package/dist-client/pages/master/material-revision-fields.d.ts +2 -0
  19. package/dist-client/pages/master/material-revision-fields.js +43 -0
  20. package/dist-client/pages/master/material-revision-fields.js.map +1 -0
  21. package/dist-client/pages/master/operational-location.js +1 -0
  22. package/dist-client/pages/master/operational-location.js.map +1 -1
  23. package/dist-client/pages/master/recipe-definition.d.ts +4 -135
  24. package/dist-client/pages/master/recipe-definition.js +7 -397
  25. package/dist-client/pages/master/recipe-definition.js.map +1 -1
  26. package/dist-client/pages/master/revision-comparison.d.ts +48 -0
  27. package/dist-client/pages/master/revision-comparison.js +553 -0
  28. package/dist-client/pages/master/revision-comparison.js.map +1 -0
  29. package/dist-client/pages/master/revision-view.d.ts +19 -0
  30. package/dist-client/pages/master/revision-view.js +133 -0
  31. package/dist-client/pages/master/revision-view.js.map +1 -0
  32. package/dist-client/pages/master/revision-workspace.d.ts +50 -0
  33. package/dist-client/pages/master/revision-workspace.js +752 -0
  34. package/dist-client/pages/master/revision-workspace.js.map +1 -0
  35. package/dist-client/pages/master/test-specification.d.ts +4 -29
  36. package/dist-client/pages/master/test-specification.js +5 -225
  37. package/dist-client/pages/master/test-specification.js.map +1 -1
  38. package/dist-client/tsconfig.tsbuildinfo +1 -1
  39. package/dist-server/service/assignment/applied-when.d.ts +24 -0
  40. package/dist-server/service/assignment/applied-when.js +16 -0
  41. package/dist-server/service/assignment/applied-when.js.map +1 -0
  42. package/dist-server/service/assignment/assignment-claim.d.ts +111 -0
  43. package/dist-server/service/assignment/assignment-claim.js +160 -0
  44. package/dist-server/service/assignment/assignment-claim.js.map +1 -0
  45. package/dist-server/service/assignment/assignment-history.d.ts +87 -0
  46. package/dist-server/service/assignment/assignment-history.js +250 -0
  47. package/dist-server/service/assignment/assignment-history.js.map +1 -0
  48. package/dist-server/service/assignment/assignment-write.d.ts +25 -0
  49. package/dist-server/service/assignment/assignment-write.js +69 -0
  50. package/dist-server/service/assignment/assignment-write.js.map +1 -0
  51. package/dist-server/service/equipment/equipment-master-resolver.d.ts +9 -1
  52. package/dist-server/service/equipment/equipment-master-resolver.js +6 -3
  53. package/dist-server/service/equipment/equipment-master-resolver.js.map +1 -1
  54. package/dist-server/service/index.d.ts +15 -2
  55. package/dist-server/service/index.js +13 -0
  56. package/dist-server/service/index.js.map +1 -1
  57. package/dist-server/service/location/location-master-resolver.d.ts +4 -1
  58. package/dist-server/service/location/location-master-resolver.js +6 -3
  59. package/dist-server/service/location/location-master-resolver.js.map +1 -1
  60. package/dist-server/service/master-axis.js +1 -1
  61. package/dist-server/service/master-axis.js.map +1 -1
  62. package/dist-server/service/master-change-policy.js +7 -2
  63. package/dist-server/service/master-change-policy.js.map +1 -1
  64. package/dist-server/service/master-conformance-resolver.js +11 -1
  65. package/dist-server/service/master-conformance-resolver.js.map +1 -1
  66. package/dist-server/service/master-crud.d.ts +11 -0
  67. package/dist-server/service/master-crud.js +15 -1
  68. package/dist-server/service/master-crud.js.map +1 -1
  69. package/dist-server/service/master-list.js +6 -0
  70. package/dist-server/service/master-list.js.map +1 -1
  71. package/dist-server/service/material/index.d.ts +3 -2
  72. package/dist-server/service/material/index.js +4 -2
  73. package/dist-server/service/material/index.js.map +1 -1
  74. package/dist-server/service/material/material-axis-status.d.ts +8 -0
  75. package/dist-server/service/material/material-axis-status.js +19 -0
  76. package/dist-server/service/material/material-axis-status.js.map +1 -0
  77. package/dist-server/service/material/material-definition.d.ts +3 -0
  78. package/dist-server/service/material/material-definition.js +13 -0
  79. package/dist-server/service/material/material-definition.js.map +1 -1
  80. package/dist-server/service/material/material-effective-list.d.ts +39 -0
  81. package/dist-server/service/material/material-effective-list.js +54 -0
  82. package/dist-server/service/material/material-effective-list.js.map +1 -0
  83. package/dist-server/service/material/material-master-resolver.js +4 -10
  84. package/dist-server/service/material/material-master-resolver.js.map +1 -1
  85. package/dist-server/service/material/material-query.js +9 -2
  86. package/dist-server/service/material/material-query.js.map +1 -1
  87. package/dist-server/service/material/material-revision-content.d.ts +10 -0
  88. package/dist-server/service/material/material-revision-content.js +92 -0
  89. package/dist-server/service/material/material-revision-content.js.map +1 -0
  90. package/dist-server/service/material/material-revision-resolver.d.ts +54 -0
  91. package/dist-server/service/material/material-revision-resolver.js +76 -0
  92. package/dist-server/service/material/material-revision-resolver.js.map +1 -0
  93. package/dist-server/service/material/material-revision-service.d.ts +144 -0
  94. package/dist-server/service/material/material-revision-service.js +547 -0
  95. package/dist-server/service/material/material-revision-service.js.map +1 -0
  96. package/dist-server/service/material/material-revision.d.ts +84 -0
  97. package/dist-server/service/material/material-revision.js +339 -0
  98. package/dist-server/service/material/material-revision.js.map +1 -0
  99. package/dist-server/service/operation/operation-definition.js +1 -0
  100. package/dist-server/service/operation/operation-definition.js.map +1 -1
  101. package/dist-server/service/operation/operation-master-resolver.js +2 -5
  102. package/dist-server/service/operation/operation-master-resolver.js.map +1 -1
  103. package/dist-server/service/recipe/index.d.ts +3 -2
  104. package/dist-server/service/recipe/index.js +4 -2
  105. package/dist-server/service/recipe/index.js.map +1 -1
  106. package/dist-server/service/recipe/recipe-definition.d.ts +4 -0
  107. package/dist-server/service/recipe/recipe-definition.js +14 -1
  108. package/dist-server/service/recipe/recipe-definition.js.map +1 -1
  109. package/dist-server/service/recipe/recipe-effective-list.d.ts +49 -0
  110. package/dist-server/service/recipe/recipe-effective-list.js +96 -0
  111. package/dist-server/service/recipe/recipe-effective-list.js.map +1 -0
  112. package/dist-server/service/recipe/recipe-query.js +9 -2
  113. package/dist-server/service/recipe/recipe-query.js.map +1 -1
  114. package/dist-server/service/recipe/recipe-revision-content.d.ts +32 -0
  115. package/dist-server/service/recipe/recipe-revision-content.js +65 -0
  116. package/dist-server/service/recipe/recipe-revision-content.js.map +1 -0
  117. package/dist-server/service/recipe/recipe-revision-line.d.ts +30 -0
  118. package/dist-server/service/recipe/recipe-revision-line.js +95 -0
  119. package/dist-server/service/recipe/recipe-revision-line.js.map +1 -0
  120. package/dist-server/service/recipe/recipe-revision-resolver.d.ts +59 -0
  121. package/dist-server/service/recipe/recipe-revision-resolver.js +76 -0
  122. package/dist-server/service/recipe/recipe-revision-resolver.js.map +1 -0
  123. package/dist-server/service/recipe/recipe-revision-service.d.ts +147 -0
  124. package/dist-server/service/recipe/recipe-revision-service.js +604 -0
  125. package/dist-server/service/recipe/recipe-revision-service.js.map +1 -0
  126. package/dist-server/service/recipe/recipe-revision.d.ts +100 -0
  127. package/dist-server/service/recipe/recipe-revision.js +373 -0
  128. package/dist-server/service/recipe/recipe-revision.js.map +1 -0
  129. package/dist-server/service/recipe/route-definition.js +1 -0
  130. package/dist-server/service/recipe/route-definition.js.map +1 -1
  131. package/dist-server/service/resource/class-members.js +9 -0
  132. package/dist-server/service/resource/class-members.js.map +1 -1
  133. package/dist-server/service/status/master-status.js +2 -1
  134. package/dist-server/service/status/master-status.js.map +1 -1
  135. package/dist-server/service/test-spec/test-spec-effective-list.d.ts +2 -0
  136. package/dist-server/service/test-spec/test-spec-effective-list.js +3 -1
  137. package/dist-server/service/test-spec/test-spec-effective-list.js.map +1 -1
  138. package/dist-server/service/test-spec/test-spec-revision-resolver.d.ts +1 -0
  139. package/dist-server/service/test-spec/test-spec-revision-service.d.ts +21 -0
  140. package/dist-server/service/test-spec/test-spec-revision-service.js +33 -0
  141. package/dist-server/service/test-spec/test-spec-revision-service.js.map +1 -1
  142. package/dist-server/service/test-spec/test-spec-revision.d.ts +2 -0
  143. package/dist-server/service/test-spec/test-spec-revision.js +6 -1
  144. package/dist-server/service/test-spec/test-spec-revision.js.map +1 -1
  145. package/dist-server/service/test-spec/test-specification.d.ts +2 -0
  146. package/dist-server/service/test-spec/test-specification.js +4 -0
  147. package/dist-server/service/test-spec/test-specification.js.map +1 -1
  148. package/dist-server/tsconfig.tsbuildinfo +1 -1
  149. package/package.json +4 -3
  150. package/translations/en.json +148 -0
  151. package/translations/ko.json +148 -0
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.claimAt = claimAt;
4
+ exports.claimsDuring = claimsDuring;
5
+ exports.recordClaim = recordClaim;
6
+ exports.projectDueClaims = projectDueClaims;
7
+ exports.valueOnRow = valueOnRow;
8
+ exports.recordInitialAssignments = recordInitialAssignments;
9
+ const typeorm_1 = require("typeorm");
10
+ const shell_1 = require("@things-factory/shell");
11
+ const master_axis_1 = require("../master-axis");
12
+ const assignment_claim_1 = require("./assignment-claim");
13
+ const assignment_write_1 = require("./assignment-write");
14
+ const ms = (at) => at.getTime();
15
+ /** 그 기록시점에 서 있던 주장들 — 물러난 것은 뺀다. */
16
+ async function standingClaims(manager, domain, target, asOfRecord) {
17
+ const rows = await manager.find(assignment_claim_1.AssignmentClaim, {
18
+ where: { domain: { id: domain.id }, axis: target.axis, rowId: target.rowId, field: target.field }
19
+ });
20
+ const at = asOfRecord ? ms(asOfRecord) : undefined;
21
+ return rows.filter(one => {
22
+ /* 그 시점 뒤에 적힌 주장은 그때 몰랐다. */
23
+ if (at !== undefined && ms(one.recordedAt) > at)
24
+ return false;
25
+ /* 그 시점에 이미 물러났으면 안 본다. 그 뒤에 물러난 것은 그때는 서 있었다. */
26
+ return !(one.supersededAt && (at === undefined || ms(one.supersededAt) <= at));
27
+ });
28
+ }
29
+ /**
30
+ * 그 업무시각에 유효했던 주장.
31
+ *
32
+ * **없으면 `undefined` 다 — 「선언 없음」과 다르다.** 선언 없음은 `value` 가 `null` 인 주장이 있는
33
+ * 것이고, 여기서 `undefined` 는 **그때 무엇이었는지 모른다**는 뜻이다.
34
+ */
35
+ async function claimAt(manager, domain, target, at) {
36
+ const standing = await standingClaims(manager, domain, target, at.asOfRecord);
37
+ const when = ms(at.asOfBusiness);
38
+ const covering = standing.filter(one => ms(one.validFrom) <= when && (!one.validTo || when < ms(one.validTo)));
39
+ if (covering.length > 1) {
40
+ throw new shell_1.Refusal('assignment-claim-conflict', { axis: target.axis, field: target.field, at: at.asOfBusiness.toISOString() }, 'two assignment claims cover the same moment. fix the history before asking.');
41
+ }
42
+ return covering[0];
43
+ }
44
+ /** 한 창을 덮는 주장들 — **계산 구간을 나눌 경계**가 여기서 나온다. 시작 시각 순이다. */
45
+ async function claimsDuring(manager, domain, target, window, asOfRecord) {
46
+ const standing = await standingClaims(manager, domain, target, asOfRecord);
47
+ const from = ms(window.from);
48
+ const to = ms(window.to);
49
+ return standing
50
+ .filter(one => ms(one.validFrom) < to && (!one.validTo || from < ms(one.validTo)))
51
+ .sort((a, b) => ms(a.validFrom) - ms(b.validFrom));
52
+ }
53
+ /**
54
+ * 주장을 남긴다. **정정이면 겹치는 것을 물러나게 하고 앞뒤 조각을 다시 주장한다.**
55
+ *
56
+ * 부르는 쪽이 마스터 변경과 **같은 트랜잭션**으로 부른다 — 갈라지면 값은 바뀌고 이력은 없는 상태가
57
+ * 생긴다.
58
+ */
59
+ async function recordClaim(manager, domain, said, now = new Date()) {
60
+ const declared = (0, assignment_claim_1.assignmentField)(said.target.axis, said.target.field);
61
+ if (!declared) {
62
+ throw new shell_1.Refusal('assignment-field-not-declared', { axis: said.target.axis, field: said.target.field }, 'this field does not keep an assignment history. declare it first.');
63
+ }
64
+ await assertUsableValue(manager, domain, declared, said, now);
65
+ const validFrom = said.validFrom ?? now;
66
+ const validTo = said.validTo;
67
+ const standing = await standingClaims(manager, domain, said.target, undefined);
68
+ const from = ms(validFrom);
69
+ const to = validTo ? ms(validTo) : undefined;
70
+ const overlapping = standing.filter(one => {
71
+ const start = ms(one.validFrom);
72
+ const end = one.validTo ? ms(one.validTo) : undefined;
73
+ return (to === undefined || start < to) && (end === undefined || from < end);
74
+ });
75
+ /*
76
+ * **읽은 뒤에 바뀌었으면 거절한다.** 부르는 쪽이 읽은 것을 주면 지금 서 있는 것과 견준다 —
77
+ * 다르면 그 사이에 누가 고친 것이고, 내 정정이 그 판단을 덮는다.
78
+ */
79
+ if (said.expecting) {
80
+ const now = new Set(overlapping.map(one => one.id));
81
+ const read = new Set(said.expecting);
82
+ const changed = now.size !== read.size || [...now].some(id => !read.has(id));
83
+ if (changed) {
84
+ throw new shell_1.Refusal('assignment-claim-superseded', { axis: said.target.axis, field: said.target.field }, 'this history changed while you were editing. read it again and decide again.');
85
+ }
86
+ }
87
+ for (const one of overlapping) {
88
+ /*
89
+ * 이미 물러난 것을 다시 물러나게 하려는 것은 **동시 정정**이다. 덮지 않고 거절한다.
90
+ */
91
+ if (one.supersededAt) {
92
+ throw new shell_1.Refusal('assignment-claim-superseded', { axis: said.target.axis, field: said.target.field }, 'this history changed while you were editing. read it again and decide again.');
93
+ }
94
+ await manager.save(assignment_claim_1.AssignmentClaim, { ...one, supersededAt: now });
95
+ /* 앞 조각 — 물러난 주장이 이 정정보다 먼저 시작했으면 그만큼은 그대로였다. */
96
+ if (ms(one.validFrom) < from) {
97
+ await manager.save(assignment_claim_1.AssignmentClaim, {
98
+ domain, axis: said.target.axis, rowId: said.target.rowId, field: said.target.field,
99
+ value: one.value ?? null, validFrom: one.validFrom, validTo: validFrom,
100
+ recordedAt: now, reason: 'remainder', recorder: said.recorder
101
+ });
102
+ }
103
+ /* 뒤 조각 — 정정이 끝난 뒤에도 그 주장이 이어졌으면 그만큼도 그대로였다. */
104
+ const end = one.validTo ? ms(one.validTo) : undefined;
105
+ if (to !== undefined && (end === undefined || end > to)) {
106
+ await manager.save(assignment_claim_1.AssignmentClaim, {
107
+ domain, axis: said.target.axis, rowId: said.target.rowId, field: said.target.field,
108
+ value: one.value ?? null, validFrom: validTo, validTo: one.validTo,
109
+ recordedAt: now, reason: 'remainder', recorder: said.recorder
110
+ });
111
+ }
112
+ }
113
+ return manager.save(assignment_claim_1.AssignmentClaim, {
114
+ domain, axis: said.target.axis, rowId: said.target.rowId, field: said.target.field,
115
+ value: said.value, validFrom, validTo, recordedAt: now, reason: said.reason, recorder: said.recorder
116
+ });
117
+ }
118
+ /**
119
+ * 도래한 미래 주장을 마스터 행에 옮긴다 — **앱의 주기 작업이 부른다.**
120
+ *
121
+ * ops-master 는 라이브러리라 스스로 돌지 않는다. 그 사이 본행은 낡아 있고, **정확해야 하는 소비처는
122
+ * 본행이 아니라 주장을 읽는다.**
123
+ */
124
+ async function projectDueClaims(manager, domain, entities, now = new Date()) {
125
+ let moved = 0;
126
+ for (const { axis, entity } of entities) {
127
+ const fields = [...new Set(ASSIGNMENT_FIELDS_OF(axis))];
128
+ for (const field of fields) {
129
+ const due = await manager.find(assignment_claim_1.AssignmentClaim, {
130
+ where: {
131
+ domain: { id: domain.id }, axis, field,
132
+ supersededAt: (0, typeorm_1.IsNull)(), validFrom: (0, typeorm_1.LessThanOrEqual)(now), reason: (0, typeorm_1.Not)('remainder')
133
+ }
134
+ });
135
+ for (const claim of due) {
136
+ const current = await claimAt(manager, domain, { axis, rowId: claim.rowId, field }, { asOfBusiness: now });
137
+ if (!current || current.id !== claim.id) {
138
+ continue;
139
+ }
140
+ const row = await manager.findOne(entity, { where: { id: claim.rowId, domain: { id: domain.id } } });
141
+ if (!row) {
142
+ continue;
143
+ }
144
+ const next = valueOnRow(claim);
145
+ if (row[field] !== next) {
146
+ await manager.save(entity, { ...row, [field]: next });
147
+ moved++;
148
+ }
149
+ }
150
+ }
151
+ }
152
+ return moved;
153
+ }
154
+ function ASSIGNMENT_FIELDS_OF(axis) {
155
+ return assignment_claim_1.ASSIGNMENT_FIELDS.filter(one => one.axis === axis).map(one => one.field);
156
+ }
157
+ /** 주장의 값을 마스터 칸이 드는 모양으로. 「선언 없음」은 `null` 이다. */
158
+ function valueOnRow(claim) {
159
+ const value = claim.value;
160
+ if (value === null || value === undefined) {
161
+ return null;
162
+ }
163
+ if (Array.isArray(value.names)) {
164
+ return value.names;
165
+ }
166
+ return value.ref ?? null;
167
+ }
168
+ /**
169
+ * 값이 이 칸의 모양인가, 그리고 **우리 도메인의 것인가.**
170
+ *
171
+ * 다른 도메인의 행을 가리키면 그 도메인이 자기 자료를 고쳐도 이쪽 과거가 흔들린다. 그리고 부모
172
+ * 관계는 **그 시점에** 도는지 본다 — 지금 안 돌아도 그때는 돌 수 있다.
173
+ */
174
+ async function assertUsableValue(manager, domain, declared, said, now) {
175
+ const value = said.value;
176
+ if (value === null || value === undefined) {
177
+ return;
178
+ }
179
+ if (declared.kind === 'names') {
180
+ if (!Array.isArray(value.names)) {
181
+ throw new shell_1.Refusal('assignment-value-shape', { field: declared.field }, 'this field takes a list of names.');
182
+ }
183
+ return;
184
+ }
185
+ const ref = value.ref;
186
+ if (typeof ref !== 'string' || !ref) {
187
+ throw new shell_1.Refusal('assignment-value-shape', { field: declared.field }, 'this field points at a row, so it needs that row identifier — not its name.');
188
+ }
189
+ const axis = master_axis_1.MASTER_AXES.find(one => one.key === declared.target);
190
+ if (!axis) {
191
+ return;
192
+ }
193
+ const pointed = await manager.findOne(axis.entity, { where: { id: ref, domain: { id: domain.id } } });
194
+ if (!pointed) {
195
+ throw new shell_1.Refusal('assignment-value-unknown', { field: declared.field, ref }, 'that row is not in this site. point at a row that is.');
196
+ }
197
+ if (declared.field === 'parentId') {
198
+ await assertNoCycleAt(manager, domain, said.target.rowId, ref, said.validFrom ?? now);
199
+ }
200
+ }
201
+ /** 그 시점의 부모 사슬을 걸어 본다. 자기 자신에 닿으면 고리다. */
202
+ async function assertNoCycleAt(manager, domain, rowId, parentRef, at) {
203
+ const walked = new Set([rowId]);
204
+ let cursor = parentRef;
205
+ while (cursor) {
206
+ if (walked.has(cursor)) {
207
+ throw new shell_1.Refusal('assignment-parent-cycle', { at: at.toISOString() }, 'this parent makes a loop at that moment. choose another parent.');
208
+ }
209
+ walked.add(cursor);
210
+ const claim = await claimAt(manager, domain, { axis: 'operationalLocation', rowId: cursor, field: 'parentId' }, { asOfBusiness: at });
211
+ cursor = claim ? (claim.value?.ref ?? undefined) : undefined;
212
+ }
213
+ }
214
+ /**
215
+ * 도입할 때 — **지금 값을 초기 상태로 적는다.**
216
+ *
217
+ * 과거를 소급해 만드는 것과 다르다. 「도입 시각에 이 값이었다는 것을 확인했다」는 주장이고, **그
218
+ * 전은 결측 그대로** 둔다. 이것이 없으면 **한 번도 안 옮긴 설비가 영영 이력이 빈다** — 그런 설비가
219
+ * 가장 많다.
220
+ *
221
+ * 이미 주장이 있는 행은 건너뛴다. 두 번 불러도 같다.
222
+ */
223
+ async function recordInitialAssignments(manager, domain, entities, at = new Date(), recorder) {
224
+ let written = 0;
225
+ for (const { axis, entity } of entities) {
226
+ const fields = assignment_claim_1.ASSIGNMENT_FIELDS.filter(one => one.axis === axis);
227
+ if (!fields.length) {
228
+ continue;
229
+ }
230
+ const rows = await manager.find(entity, { where: { domain: { id: domain.id } } });
231
+ for (const row of rows) {
232
+ for (const declared of fields) {
233
+ const already = await manager.findOne(assignment_claim_1.AssignmentClaim, {
234
+ where: { domain: { id: domain.id }, axis, rowId: String(row.id), field: declared.field }
235
+ });
236
+ if (already) {
237
+ continue;
238
+ }
239
+ await manager.save(assignment_claim_1.AssignmentClaim, {
240
+ domain, axis, rowId: String(row.id), field: declared.field,
241
+ value: (0, assignment_write_1.toClaimValue)(declared.kind, row[declared.field]),
242
+ validFrom: at, recordedAt: at, reason: 'initial', recorder
243
+ });
244
+ written++;
245
+ }
246
+ }
247
+ }
248
+ return written;
249
+ }
250
+ //# sourceMappingURL=assignment-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assignment-history.js","sourceRoot":"","sources":["../../../server/service/assignment/assignment-history.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, IsNull, LessThanOrEqual, Not, ObjectLiteral } from 'typeorm'\nimport { Domain, Refusal } from '@things-factory/shell'\nimport { MASTER_AXES } from '../master-axis'\n\nimport { ASSIGNMENT_FIELDS, AssignmentClaim, assignmentField } from './assignment-claim'\nimport { toClaimValue } from './assignment-write'\n\n/**\n * 주장을 남기고 읽는 규칙 — **덮어쓰지 않는다.**\n *\n * ── 정정이 양옆을 남긴다 ───────────────────────────────────────────────────\n * 겹치는 주장을 물러나게 하는 것만으로는 모자란다. `A [1일, ∞)` 에 「10~15는 B」를 정정하면 A 의\n * **앞뒤 조각을 같은 값으로 다시 주장**해야 최신 답이 `A·B·A` 가 된다. 조각도 새 주장이므로 정정 전\n * 기록시점으로 읽으면 원래 A 하나가 그대로 나온다.\n *\n * ── 동시 정정은 거절한다 ───────────────────────────────────────────────────\n * 물러나게 하려던 주장이 이미 물러나 있으면 충돌이다. **자동으로 다시 시도하지 않는다** — 덮으면\n * 한쪽의 판단이 사라진다. 다시 읽고 다시 정하는 것은 사람의 일이다.\n */\n\nexport interface ClaimAt {\n /** 어느 업무시각의 이야기인가. */\n asOfBusiness: Date\n /** 어느 기록시점까지 알려진 것만 볼 것인가. 안 주면 지금까지 아는 전부다. */\n asOfRecord?: Date\n}\n\nexport interface ClaimTarget {\n axis: string\n rowId: string\n field: string\n}\n\nconst ms = (at: Date) => at.getTime()\n\n/** 그 기록시점에 서 있던 주장들 — 물러난 것은 뺀다. */\nasync function standingClaims(\n manager: EntityManager,\n domain: Domain,\n target: ClaimTarget,\n asOfRecord?: Date\n): Promise<AssignmentClaim[]> {\n const rows = await manager.find(AssignmentClaim, {\n where: { domain: { id: domain.id }, axis: target.axis, rowId: target.rowId, field: target.field }\n })\n\n const at = asOfRecord ? ms(asOfRecord) : undefined\n\n return rows.filter(one => {\n /* 그 시점 뒤에 적힌 주장은 그때 몰랐다. */\n if (at !== undefined && ms(one.recordedAt) > at) return false\n\n /* 그 시점에 이미 물러났으면 안 본다. 그 뒤에 물러난 것은 그때는 서 있었다. */\n return !(one.supersededAt && (at === undefined || ms(one.supersededAt) <= at))\n })\n}\n\n/**\n * 그 업무시각에 유효했던 주장.\n *\n * **없으면 `undefined` 다 — 「선언 없음」과 다르다.** 선언 없음은 `value` 가 `null` 인 주장이 있는\n * 것이고, 여기서 `undefined` 는 **그때 무엇이었는지 모른다**는 뜻이다.\n */\nexport async function claimAt(\n manager: EntityManager,\n domain: Domain,\n target: ClaimTarget,\n at: ClaimAt\n): Promise<AssignmentClaim | undefined> {\n const standing = await standingClaims(manager, domain, target, at.asOfRecord)\n const when = ms(at.asOfBusiness)\n\n const covering = standing.filter(one => ms(one.validFrom) <= when && (!one.validTo || when < ms(one.validTo)))\n\n if (covering.length > 1) {\n throw new Refusal(\n 'assignment-claim-conflict',\n { axis: target.axis, field: target.field, at: at.asOfBusiness.toISOString() },\n 'two assignment claims cover the same moment. fix the history before asking.'\n )\n }\n\n return covering[0]\n}\n\n/** 한 창을 덮는 주장들 — **계산 구간을 나눌 경계**가 여기서 나온다. 시작 시각 순이다. */\nexport async function claimsDuring(\n manager: EntityManager,\n domain: Domain,\n target: ClaimTarget,\n window: { from: Date; to: Date },\n asOfRecord?: Date\n): Promise<AssignmentClaim[]> {\n const standing = await standingClaims(manager, domain, target, asOfRecord)\n const from = ms(window.from)\n const to = ms(window.to)\n\n return standing\n .filter(one => ms(one.validFrom) < to && (!one.validTo || from < ms(one.validTo)))\n .sort((a, b) => ms(a.validFrom) - ms(b.validFrom))\n}\n\nexport interface RecordClaim {\n target: ClaimTarget\n value: Record<string, unknown> | null\n /** 언제부터 그러한가. 안 주면 지금부터다 — 그 기본값이 곧 「지금부터」라는 주장이다. */\n validFrom?: Date\n /** 언제까지. 정정에서만 쓴다. */\n validTo?: Date\n reason: 'initial' | 'change' | 'correction'\n recorder?: unknown\n /**\n * 내가 읽었을 때 서 있던 주장들의 id.\n *\n * 주면 **그 사이에 누가 바꿨는지** 본다 — 화면에서 읽고 고치는 동안 다른 사람이 같은 구간을\n * 정정했으면 내 정정이 그것을 덮는다. 덮지 않고 거절한다.\n */\n expecting?: readonly string[]\n}\n\n/**\n * 주장을 남긴다. **정정이면 겹치는 것을 물러나게 하고 앞뒤 조각을 다시 주장한다.**\n *\n * 부르는 쪽이 마스터 변경과 **같은 트랜잭션**으로 부른다 — 갈라지면 값은 바뀌고 이력은 없는 상태가\n * 생긴다.\n */\nexport async function recordClaim(\n manager: EntityManager,\n domain: Domain,\n said: RecordClaim,\n now = new Date()\n): Promise<AssignmentClaim> {\n const declared = assignmentField(said.target.axis, said.target.field)\n\n if (!declared) {\n throw new Refusal(\n 'assignment-field-not-declared',\n { axis: said.target.axis, field: said.target.field },\n 'this field does not keep an assignment history. declare it first.'\n )\n }\n\n await assertUsableValue(manager, domain, declared, said, now)\n\n const validFrom = said.validFrom ?? now\n const validTo = said.validTo\n const standing = await standingClaims(manager, domain, said.target, undefined)\n const from = ms(validFrom)\n const to = validTo ? ms(validTo) : undefined\n\n const overlapping = standing.filter(one => {\n const start = ms(one.validFrom)\n const end = one.validTo ? ms(one.validTo) : undefined\n\n return (to === undefined || start < to) && (end === undefined || from < end)\n })\n\n /*\n * **읽은 뒤에 바뀌었으면 거절한다.** 부르는 쪽이 읽은 것을 주면 지금 서 있는 것과 견준다 —\n * 다르면 그 사이에 누가 고친 것이고, 내 정정이 그 판단을 덮는다.\n */\n if (said.expecting) {\n const now = new Set(overlapping.map(one => one.id))\n const read = new Set(said.expecting)\n const changed = now.size !== read.size || [...now].some(id => !read.has(id))\n\n if (changed) {\n throw new Refusal(\n 'assignment-claim-superseded',\n { axis: said.target.axis, field: said.target.field },\n 'this history changed while you were editing. read it again and decide again.'\n )\n }\n }\n\n for (const one of overlapping) {\n /*\n * 이미 물러난 것을 다시 물러나게 하려는 것은 **동시 정정**이다. 덮지 않고 거절한다.\n */\n if (one.supersededAt) {\n throw new Refusal(\n 'assignment-claim-superseded',\n { axis: said.target.axis, field: said.target.field },\n 'this history changed while you were editing. read it again and decide again.'\n )\n }\n\n await manager.save(AssignmentClaim, { ...one, supersededAt: now })\n\n /* 앞 조각 — 물러난 주장이 이 정정보다 먼저 시작했으면 그만큼은 그대로였다. */\n if (ms(one.validFrom) < from) {\n await manager.save(AssignmentClaim, {\n domain, axis: said.target.axis, rowId: said.target.rowId, field: said.target.field,\n value: one.value ?? null, validFrom: one.validFrom, validTo: validFrom,\n recordedAt: now, reason: 'remainder', recorder: said.recorder\n } as Partial<AssignmentClaim>)\n }\n\n /* 뒤 조각 — 정정이 끝난 뒤에도 그 주장이 이어졌으면 그만큼도 그대로였다. */\n const end = one.validTo ? ms(one.validTo) : undefined\n\n if (to !== undefined && (end === undefined || end > to)) {\n await manager.save(AssignmentClaim, {\n domain, axis: said.target.axis, rowId: said.target.rowId, field: said.target.field,\n value: one.value ?? null, validFrom: validTo as Date, validTo: one.validTo,\n recordedAt: now, reason: 'remainder', recorder: said.recorder\n } as Partial<AssignmentClaim>)\n }\n }\n\n return manager.save(AssignmentClaim, {\n domain, axis: said.target.axis, rowId: said.target.rowId, field: said.target.field,\n value: said.value, validFrom, validTo, recordedAt: now, reason: said.reason, recorder: said.recorder\n } as Partial<AssignmentClaim>)\n}\n\n/**\n * 도래한 미래 주장을 마스터 행에 옮긴다 — **앱의 주기 작업이 부른다.**\n *\n * ops-master 는 라이브러리라 스스로 돌지 않는다. 그 사이 본행은 낡아 있고, **정확해야 하는 소비처는\n * 본행이 아니라 주장을 읽는다.**\n */\nexport async function projectDueClaims(\n manager: EntityManager,\n domain: Domain,\n entities: { axis: string; entity: Function }[],\n now = new Date()\n): Promise<number> {\n let moved = 0\n\n for (const { axis, entity } of entities) {\n const fields = [...new Set(ASSIGNMENT_FIELDS_OF(axis))]\n\n for (const field of fields) {\n const due = await manager.find(AssignmentClaim, {\n where: {\n domain: { id: domain.id }, axis, field,\n supersededAt: IsNull(), validFrom: LessThanOrEqual(now), reason: Not('remainder')\n }\n })\n\n for (const claim of due) {\n const current = await claimAt(manager, domain, { axis, rowId: claim.rowId, field }, { asOfBusiness: now })\n\n if (!current || current.id !== claim.id) {\n continue\n }\n\n const row = await manager.findOne(entity as never, { where: { id: claim.rowId, domain: { id: domain.id } } } as never)\n\n if (!row) {\n continue\n }\n\n const next = valueOnRow(claim)\n\n if ((row as Record<string, unknown>)[field] !== next) {\n await manager.save(entity as never, { ...(row as object), [field]: next } as never)\n moved++\n }\n }\n }\n }\n\n return moved\n}\n\nfunction ASSIGNMENT_FIELDS_OF(axis: string): string[] {\n return ASSIGNMENT_FIELDS.filter(one => one.axis === axis).map(one => one.field)\n}\n\n/** 주장의 값을 마스터 칸이 드는 모양으로. 「선언 없음」은 `null` 이다. */\nexport function valueOnRow(claim: AssignmentClaim): unknown {\n const value = claim.value\n\n if (value === null || value === undefined) {\n return null\n }\n\n if (Array.isArray((value as { names?: unknown }).names)) {\n return (value as { names: unknown[] }).names\n }\n\n return (value as { ref?: unknown }).ref ?? null\n}\n\n/**\n * 값이 이 칸의 모양인가, 그리고 **우리 도메인의 것인가.**\n *\n * 다른 도메인의 행을 가리키면 그 도메인이 자기 자료를 고쳐도 이쪽 과거가 흔들린다. 그리고 부모\n * 관계는 **그 시점에** 도는지 본다 — 지금 안 돌아도 그때는 돌 수 있다.\n */\nasync function assertUsableValue(\n manager: EntityManager,\n domain: Domain,\n declared: { axis: string; field: string; kind: 'relation' | 'names'; target?: string },\n said: RecordClaim,\n now: Date\n): Promise<void> {\n const value = said.value\n\n if (value === null || value === undefined) {\n return\n }\n\n if (declared.kind === 'names') {\n if (!Array.isArray((value as { names?: unknown }).names)) {\n throw new Refusal('assignment-value-shape', { field: declared.field }, 'this field takes a list of names.')\n }\n\n return\n }\n\n const ref = (value as { ref?: unknown }).ref\n\n if (typeof ref !== 'string' || !ref) {\n throw new Refusal(\n 'assignment-value-shape',\n { field: declared.field },\n 'this field points at a row, so it needs that row identifier — not its name.'\n )\n }\n\n const axis = MASTER_AXES.find(one => one.key === declared.target)\n\n if (!axis) {\n return\n }\n\n const pointed = await manager.findOne(axis.entity as never, { where: { id: ref, domain: { id: domain.id } } } as never)\n\n if (!pointed) {\n throw new Refusal(\n 'assignment-value-unknown',\n { field: declared.field, ref },\n 'that row is not in this site. point at a row that is.'\n )\n }\n\n if (declared.field === 'parentId') {\n await assertNoCycleAt(manager, domain, said.target.rowId, ref, said.validFrom ?? now)\n }\n}\n\n/** 그 시점의 부모 사슬을 걸어 본다. 자기 자신에 닿으면 고리다. */\nasync function assertNoCycleAt(\n manager: EntityManager,\n domain: Domain,\n rowId: string,\n parentRef: string,\n at: Date\n): Promise<void> {\n const walked = new Set<string>([rowId])\n let cursor: string | undefined = parentRef\n\n while (cursor) {\n if (walked.has(cursor)) {\n throw new Refusal(\n 'assignment-parent-cycle',\n { at: at.toISOString() },\n 'this parent makes a loop at that moment. choose another parent.'\n )\n }\n\n walked.add(cursor)\n\n const claim = await claimAt(manager, domain, { axis: 'operationalLocation', rowId: cursor, field: 'parentId' }, { asOfBusiness: at })\n\n cursor = claim ? ((claim.value as { ref?: string } | null)?.ref ?? undefined) : undefined\n }\n}\n\n/**\n * 도입할 때 — **지금 값을 초기 상태로 적는다.**\n *\n * 과거를 소급해 만드는 것과 다르다. 「도입 시각에 이 값이었다는 것을 확인했다」는 주장이고, **그\n * 전은 결측 그대로** 둔다. 이것이 없으면 **한 번도 안 옮긴 설비가 영영 이력이 빈다** — 그런 설비가\n * 가장 많다.\n *\n * 이미 주장이 있는 행은 건너뛴다. 두 번 불러도 같다.\n */\nexport async function recordInitialAssignments(\n manager: EntityManager,\n domain: Domain,\n entities: { axis: string; entity: Function }[],\n at = new Date(),\n recorder?: unknown\n): Promise<number> {\n let written = 0\n\n for (const { axis, entity } of entities) {\n const fields = ASSIGNMENT_FIELDS.filter(one => one.axis === axis)\n\n if (!fields.length) {\n continue\n }\n\n const rows: ObjectLiteral[] = await manager.find(entity as never, { where: { domain: { id: domain.id } } } as never)\n\n for (const row of rows) {\n for (const declared of fields) {\n const already = await manager.findOne(AssignmentClaim, {\n where: { domain: { id: domain.id }, axis, rowId: String(row.id), field: declared.field }\n })\n\n if (already) {\n continue\n }\n\n await manager.save(AssignmentClaim, {\n domain, axis, rowId: String(row.id), field: declared.field,\n value: toClaimValue(declared.kind, row[declared.field]),\n validFrom: at, recordedAt: at, reason: 'initial', recorder\n } as Partial<AssignmentClaim>)\n written++\n }\n }\n }\n\n return written\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { EntityManager, ObjectLiteral } from 'typeorm';
2
+ import { Domain } from '@things-factory/shell';
3
+ import { assignmentField } from './assignment-claim';
4
+ /**
5
+ * 그리드가 보낸 변경에서 **배정·선언 칸을 골라 주장으로 남긴다.**
6
+ *
7
+ * ── 왜 본행을 되돌려 놓나 ──────────────────────────────────────────────────
8
+ * 적용 시각이 미래면 **본행은 그대로여야 한다.** 그리드는 값을 보냈지만 그것은 「다음 달부터」라는
9
+ * 뜻이고, 오늘의 값이 아니다. 그래서 `keepOnRow` 로 옛 값을 되돌려 저장에 얹는다 — 도래하면
10
+ * `projectDueClaims` 가 옮긴다.
11
+ *
12
+ * ── 마스터 변경과 한 트랜잭션이다 ──────────────────────────────────────────
13
+ * 부르는 쪽이 `saveMasterPatches` 안이므로 같은 `manager` 다. 갈라지면 값은 바뀌고 이력은 없는
14
+ * 상태가 생긴다.
15
+ */
16
+ export declare function claimAssignmentChanges(manager: EntityManager, domain: Domain, axis: string, found: ObjectLiteral, values: ObjectLiteral, user: unknown, options: {
17
+ appliedAt?: Date;
18
+ appliedKind?: 'change' | 'correction';
19
+ appliedUntil?: Date;
20
+ }): Promise<{
21
+ keepOnRow: ObjectLiteral;
22
+ }>;
23
+ /** 마스터 칸의 값 → 주장의 값. 「선언 없음」은 `null` 이다. */
24
+ export declare function toClaimValue(kind: 'relation' | 'names', value: unknown): Record<string, unknown> | null;
25
+ export { assignmentField };
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assignmentField = void 0;
4
+ exports.claimAssignmentChanges = claimAssignmentChanges;
5
+ exports.toClaimValue = toClaimValue;
6
+ const assignment_claim_1 = require("./assignment-claim");
7
+ Object.defineProperty(exports, "assignmentField", { enumerable: true, get: function () { return assignment_claim_1.assignmentField; } });
8
+ const assignment_history_1 = require("./assignment-history");
9
+ /**
10
+ * 그리드가 보낸 변경에서 **배정·선언 칸을 골라 주장으로 남긴다.**
11
+ *
12
+ * ── 왜 본행을 되돌려 놓나 ──────────────────────────────────────────────────
13
+ * 적용 시각이 미래면 **본행은 그대로여야 한다.** 그리드는 값을 보냈지만 그것은 「다음 달부터」라는
14
+ * 뜻이고, 오늘의 값이 아니다. 그래서 `keepOnRow` 로 옛 값을 되돌려 저장에 얹는다 — 도래하면
15
+ * `projectDueClaims` 가 옮긴다.
16
+ *
17
+ * ── 마스터 변경과 한 트랜잭션이다 ──────────────────────────────────────────
18
+ * 부르는 쪽이 `saveMasterPatches` 안이므로 같은 `manager` 다. 갈라지면 값은 바뀌고 이력은 없는
19
+ * 상태가 생긴다.
20
+ */
21
+ async function claimAssignmentChanges(manager, domain, axis, found, values, user, options) {
22
+ const keepOnRow = {};
23
+ const fields = assignment_claim_1.ASSIGNMENT_FIELDS.filter(one => one.axis === axis);
24
+ if (!fields.length) {
25
+ return { keepOnRow };
26
+ }
27
+ const now = new Date();
28
+ const appliedAt = options.appliedAt ?? now;
29
+ const future = appliedAt.getTime() > now.getTime();
30
+ for (const declared of fields) {
31
+ if (!(declared.field in values)) {
32
+ continue;
33
+ }
34
+ const next = values[declared.field];
35
+ /* 안 바뀐 칸은 주장을 남기지 않는다 — 같은 값을 다시 적으면 이력이 뜻 없이 길어진다. */
36
+ if (sameValue(found[declared.field], next)) {
37
+ continue;
38
+ }
39
+ await (0, assignment_history_1.recordClaim)(manager, domain, {
40
+ target: { axis, rowId: String(found.id), field: declared.field },
41
+ value: toClaimValue(declared.kind, next),
42
+ validFrom: appliedAt,
43
+ validTo: options.appliedUntil,
44
+ reason: options.appliedKind === 'correction' ? 'correction' : 'change',
45
+ recorder: user
46
+ }, now);
47
+ if (future) {
48
+ keepOnRow[declared.field] = found[declared.field] ?? null;
49
+ }
50
+ }
51
+ return { keepOnRow };
52
+ }
53
+ /** 마스터 칸의 값 → 주장의 값. 「선언 없음」은 `null` 이다. */
54
+ function toClaimValue(kind, value) {
55
+ if (value === null || value === undefined || value === '') {
56
+ return null;
57
+ }
58
+ if (kind === 'names') {
59
+ return { names: Array.isArray(value) ? value.map(String) : [String(value)] };
60
+ }
61
+ return { ref: String(value) };
62
+ }
63
+ function sameValue(before, after) {
64
+ if (Array.isArray(before) || Array.isArray(after)) {
65
+ return JSON.stringify(before ?? null) === JSON.stringify(after ?? null);
66
+ }
67
+ return (before ?? null) === (after ?? null);
68
+ }
69
+ //# sourceMappingURL=assignment-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assignment-write.js","sourceRoot":"","sources":["../../../server/service/assignment/assignment-write.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, ObjectLiteral } from 'typeorm'\nimport { Domain } from '@things-factory/shell'\n\nimport { ASSIGNMENT_FIELDS, assignmentField } from './assignment-claim'\nimport { recordClaim } from './assignment-history'\n\n/**\n * 그리드가 보낸 변경에서 **배정·선언 칸을 골라 주장으로 남긴다.**\n *\n * ── 왜 본행을 되돌려 놓나 ──────────────────────────────────────────────────\n * 적용 시각이 미래면 **본행은 그대로여야 한다.** 그리드는 값을 보냈지만 그것은 「다음 달부터」라는\n * 뜻이고, 오늘의 값이 아니다. 그래서 `keepOnRow` 로 옛 값을 되돌려 저장에 얹는다 — 도래하면\n * `projectDueClaims` 가 옮긴다.\n *\n * ── 마스터 변경과 한 트랜잭션이다 ──────────────────────────────────────────\n * 부르는 쪽이 `saveMasterPatches` 안이므로 같은 `manager` 다. 갈라지면 값은 바뀌고 이력은 없는\n * 상태가 생긴다.\n */\nexport async function claimAssignmentChanges(\n manager: EntityManager,\n domain: Domain,\n axis: string,\n found: ObjectLiteral,\n values: ObjectLiteral,\n user: unknown,\n options: { appliedAt?: Date; appliedKind?: 'change' | 'correction'; appliedUntil?: Date }\n): Promise<{ keepOnRow: ObjectLiteral }> {\n const keepOnRow: ObjectLiteral = {}\n const fields = ASSIGNMENT_FIELDS.filter(one => one.axis === axis)\n\n if (!fields.length) {\n return { keepOnRow }\n }\n\n const now = new Date()\n const appliedAt = options.appliedAt ?? now\n const future = appliedAt.getTime() > now.getTime()\n\n for (const declared of fields) {\n if (!(declared.field in values)) {\n continue\n }\n\n const next = values[declared.field]\n\n /* 안 바뀐 칸은 주장을 남기지 않는다 — 같은 값을 다시 적으면 이력이 뜻 없이 길어진다. */\n if (sameValue(found[declared.field], next)) {\n continue\n }\n\n await recordClaim(\n manager,\n domain,\n {\n target: { axis, rowId: String(found.id), field: declared.field },\n value: toClaimValue(declared.kind, next),\n validFrom: appliedAt,\n validTo: options.appliedUntil,\n reason: options.appliedKind === 'correction' ? 'correction' : 'change',\n recorder: user\n },\n now\n )\n\n if (future) {\n keepOnRow[declared.field] = found[declared.field] ?? null\n }\n }\n\n return { keepOnRow }\n}\n\n/** 마스터 칸의 값 → 주장의 값. 「선언 없음」은 `null` 이다. */\nexport function toClaimValue(kind: 'relation' | 'names', value: unknown): Record<string, unknown> | null {\n if (value === null || value === undefined || value === '') {\n return null\n }\n\n if (kind === 'names') {\n return { names: Array.isArray(value) ? value.map(String) : [String(value)] }\n }\n\n return { ref: String(value) }\n}\n\nfunction sameValue(before: unknown, after: unknown): boolean {\n if (Array.isArray(before) || Array.isArray(after)) {\n return JSON.stringify(before ?? null) === JSON.stringify(after ?? null)\n }\n\n return (before ?? null) === (after ?? null)\n}\n\nexport { assignmentField }\n"]}
@@ -1,3 +1,4 @@
1
+ import { AppliedWhen } from '../assignment/applied-when';
1
2
  import { ListParam } from '@things-factory/shell';
2
3
  import { MasterPatch } from '../master-crud';
3
4
  import { EquipmentClass } from './equipment-class';
@@ -50,7 +51,14 @@ export declare class EquipmentResolver {
50
51
  * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는
51
52
  * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.
52
53
  */
53
- updateMultipleEquipment(patches: MasterPatch[], context: ResolverContext): Promise<Equipment[]>;
54
+ updateMultipleEquipment(patches: MasterPatch[], context: ResolverContext,
55
+ /**
56
+ * **언제부터 그러한가** — 배정·선언 칸을 고칠 때만 온다.
57
+ *
58
+ * 안 오면 지금부터다. 미래면 주장만 남고 본행은 그 시각이 올 때까지 그대로다
59
+ * (§`claimAssignmentChanges`).
60
+ */
61
+ applied?: AppliedWhen): Promise<Equipment[]>;
54
62
  }
55
63
  export declare class StopReasonList {
56
64
  items: StopReason[];
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StopReasonResolver = exports.StopReasonList = exports.EquipmentResolver = exports.EquipmentList = exports.EquipmentClassResolver = exports.EquipmentClassList = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const type_graphql_1 = require("type-graphql");
6
+ const applied_when_1 = require("../assignment/applied-when");
6
7
  const shell_1 = require("@things-factory/shell");
7
8
  const type_graphql_2 = require("type-graphql");
8
9
  const state_period_rules_js_1 = require("./state-period-rules.js");
@@ -153,11 +154,12 @@ let EquipmentResolver = class EquipmentResolver {
153
154
  * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는
154
155
  * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.
155
156
  */
156
- async updateMultipleEquipment(patches, context) {
157
+ async updateMultipleEquipment(patches, context, applied) {
157
158
  const { domain, user, tx } = context.state;
158
159
  const axis = (0, master_axis_1.masterAxisOf)('equipment');
159
160
  const saved = await (0, master_crud_1.saveMasterPatches)(tx, domain, axis.entity, patches, user, {
160
- hasEffectivePeriod: axis.hasEffectivePeriod
161
+ hasEffectivePeriod: axis.hasEffectivePeriod,
162
+ ...(0, applied_when_1.appliedOptions)(applied)
161
163
  });
162
164
  return saved;
163
165
  }
@@ -178,8 +180,9 @@ tslib_1.__decorate([
178
180
  (0, type_graphql_2.Mutation)(returns => [equipment_1.Equipment], { description: 'To create, change or retire equipment' }),
179
181
  tslib_1.__param(0, (0, type_graphql_2.Arg)('patches', type => [shell_2.ScalarObject])),
180
182
  tslib_1.__param(1, (0, type_graphql_2.Ctx)()),
183
+ tslib_1.__param(2, (0, type_graphql_2.Arg)('applied', type => shell_2.ScalarObject, { nullable: true })),
181
184
  tslib_1.__metadata("design:type", Function),
182
- tslib_1.__metadata("design:paramtypes", [Array, Object]),
185
+ tslib_1.__metadata("design:paramtypes", [Array, Object, Object]),
183
186
  tslib_1.__metadata("design:returntype", Promise)
184
187
  ], EquipmentResolver.prototype, "updateMultipleEquipment", null);
185
188
  exports.EquipmentResolver = EquipmentResolver = tslib_1.__decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"equipment-master-resolver.js","sourceRoot":"","sources":["../../../server/service/equipment/equipment-master-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { UseMiddleware } from 'type-graphql'\nimport { SpeakRefusals } from '@things-factory/shell'\nimport { FieldResolver, Root, Args, Arg, Ctx, Directive, Int, Mutation, ObjectType, Field, Query, Resolver } from 'type-graphql'\nimport { stopReasonStatusGap } from './state-period-rules.js'\n\nimport { Domain, ListParam, ScalarObject } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { ClassMembers, scanClassMembers } from '../resource/class-members'\nimport { EquipmentClass } from './equipment-class'\nimport { Equipment } from './equipment'\nimport { StopReason } from './stop-reason'\n\n/**\n * 설비 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of equipment classes' })\nexport class EquipmentClassList {\n @Field(type => [EquipmentClass])\n items: EquipmentClass[]\n\n @Field(type => Int)\n total: number\n}\n\n/**\n * **이 등급에 무엇이 드나** — 들어오는 관계.\n *\n * 등급을 만들어 놓고 아무도 안 들어 있는 일이 실제로 있었다. 화면에는 등급 이름만 있어서 그 사실이\n * 안 보였다. 없앨 때 무엇이 딸려 자격을 잃는지도 알 수 없었다.\n *\n * 세는 방식과 상한은 `class-members.ts` 머리말에 적었다 — 등급 넷이 같은 함수를 쓴다.\n */\nfunction equipmentClassMembersOf(context: ResolverContext): Promise<ClassMembers> {\n const state = context.state as { domain: Domain; equipmentClassMembers?: Promise<ClassMembers> }\n\n state.equipmentClassMembers = state.equipmentClassMembers || scanClassMembers(Equipment, 'equipmentClassIds', state.domain)\n\n return state.equipmentClassMembers\n}\n\n@Resolver(EquipmentClass)\n@UseMiddleware(SpeakRefusals)\nexport class EquipmentClassResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EquipmentClassList, { description: 'To fetch equipment classes' })\n async equipmentClasses(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EquipmentClassList> {\n const { domain } = context.state\n const { items, total } = await listMaster('equipmentClass', params, domain)\n\n return { items: items as EquipmentClass[], total }\n }\n\n /**\n * 이 등급에 든 설비들\n *\n * 아무도 안 들면 빈 목록이다. 다만 그것이 「없다」인지 「다 못 봤다」인지는 `memberScanCapped`\n * 가 말한다 — 조용히 자르면 고쳐야 할 선언과 멀쩡한 등급이 같아 보인다.\n */\n @FieldResolver(type => [String], { description: 'Equipment belonging to this class' })\n async members(@Root() klass: EquipmentClass, @Ctx() context: ResolverContext): Promise<string[]> {\n return (await equipmentClassMembersOf(context)).members.get(klass.name) ?? []\n }\n\n /** 소속을 다 보지 못했나. */\n @FieldResolver(type => Boolean, { description: 'True when members were too many to scan fully' })\n async memberScanCapped(@Root() klass: EquipmentClass, @Ctx() context: ResolverContext): Promise<boolean> {\n return (await equipmentClassMembersOf(context)).capped\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [EquipmentClass], { description: 'To create, change or retire equipment classes' })\n async updateMultipleEquipmentClass(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<EquipmentClass[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('equipmentClass')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as EquipmentClass[]\n }\n}\n\n@ObjectType({ description: 'A page of equipment' })\nexport class EquipmentList {\n @Field(type => [Equipment])\n items: Equipment[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(Equipment)\n@UseMiddleware(SpeakRefusals)\nexport class EquipmentResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EquipmentList, { description: 'To fetch equipment' })\n async equipmentList(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EquipmentList> {\n const { domain } = context.state\n const { items, total } = await listMaster('equipment', params, domain)\n\n return { items: items as Equipment[], total }\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [Equipment], { description: 'To create, change or retire equipment' })\n async updateMultipleEquipment(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<Equipment[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('equipment')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as Equipment[]\n }\n}\n\n@ObjectType({ description: 'A page of stop reasons' })\nexport class StopReasonList {\n @Field(type => [StopReason])\n items: StopReason[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(StopReason)\n@UseMiddleware(SpeakRefusals)\nexport class StopReasonResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => StopReasonList, { description: 'To fetch stop reasons' })\n async stopReasonList(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<StopReasonList> {\n const { domain } = context.state\n const { items, total } = await listMaster('stopReason', params, domain)\n\n return { items: items as StopReason[], total }\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [StopReason], { description: 'To create, change or retire stop reasons' })\n async updateMultipleStopReason(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<StopReason[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('stopReason')\n\n /*\n * **모르는 상태로는 저장하지 않는다.** 이 값이 가동률을 깎느냐 마느냐를 정하므로, 목록 밖 값이\n * 들어오면 그 사유를 쓴 구간이 전부 어긋남으로 걸린다 — 잘못은 여기서 났는데 불은 거기서 켜진다.\n *\n * 지우는 패치(`retire`)는 상태를 다시 말하지 않으므로 값이 있을 때만 본다.\n */\n for (const patch of patches) {\n const said = (patch as any)?.status\n if (said === undefined || said === null) continue\n\n const gap = stopReasonStatusGap(said)\n if (gap) throw new Error(`정지 사유 \"${(patch as any)?.name ?? ''}\" — ${gap}`)\n }\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as StopReason[]\n }\n}\n"]}
1
+ {"version":3,"file":"equipment-master-resolver.js","sourceRoot":"","sources":["../../../server/service/equipment/equipment-master-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { UseMiddleware } from 'type-graphql'\nimport { AppliedWhen, appliedOptions } from '../assignment/applied-when'\nimport { SpeakRefusals } from '@things-factory/shell'\nimport { FieldResolver, Root, Args, Arg, Ctx, Directive, Int, Mutation, ObjectType, Field, Query, Resolver } from 'type-graphql'\nimport { stopReasonStatusGap } from './state-period-rules.js'\n\nimport { Domain, ListParam, ScalarObject } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { ClassMembers, scanClassMembers } from '../resource/class-members'\nimport { EquipmentClass } from './equipment-class'\nimport { Equipment } from './equipment'\nimport { StopReason } from './stop-reason'\n\n/**\n * 설비 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of equipment classes' })\nexport class EquipmentClassList {\n @Field(type => [EquipmentClass])\n items: EquipmentClass[]\n\n @Field(type => Int)\n total: number\n}\n\n/**\n * **이 등급에 무엇이 드나** — 들어오는 관계.\n *\n * 등급을 만들어 놓고 아무도 안 들어 있는 일이 실제로 있었다. 화면에는 등급 이름만 있어서 그 사실이\n * 안 보였다. 없앨 때 무엇이 딸려 자격을 잃는지도 알 수 없었다.\n *\n * 세는 방식과 상한은 `class-members.ts` 머리말에 적었다 — 등급 넷이 같은 함수를 쓴다.\n */\nfunction equipmentClassMembersOf(context: ResolverContext): Promise<ClassMembers> {\n const state = context.state as { domain: Domain; equipmentClassMembers?: Promise<ClassMembers> }\n\n state.equipmentClassMembers = state.equipmentClassMembers || scanClassMembers(Equipment, 'equipmentClassIds', state.domain)\n\n return state.equipmentClassMembers\n}\n\n@Resolver(EquipmentClass)\n@UseMiddleware(SpeakRefusals)\nexport class EquipmentClassResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EquipmentClassList, { description: 'To fetch equipment classes' })\n async equipmentClasses(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EquipmentClassList> {\n const { domain } = context.state\n const { items, total } = await listMaster('equipmentClass', params, domain)\n\n return { items: items as EquipmentClass[], total }\n }\n\n /**\n * 이 등급에 든 설비들\n *\n * 아무도 안 들면 빈 목록이다. 다만 그것이 「없다」인지 「다 못 봤다」인지는 `memberScanCapped`\n * 가 말한다 — 조용히 자르면 고쳐야 할 선언과 멀쩡한 등급이 같아 보인다.\n */\n @FieldResolver(type => [String], { description: 'Equipment belonging to this class' })\n async members(@Root() klass: EquipmentClass, @Ctx() context: ResolverContext): Promise<string[]> {\n return (await equipmentClassMembersOf(context)).members.get(klass.name) ?? []\n }\n\n /** 소속을 다 보지 못했나. */\n @FieldResolver(type => Boolean, { description: 'True when members were too many to scan fully' })\n async memberScanCapped(@Root() klass: EquipmentClass, @Ctx() context: ResolverContext): Promise<boolean> {\n return (await equipmentClassMembersOf(context)).capped\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [EquipmentClass], { description: 'To create, change or retire equipment classes' })\n async updateMultipleEquipmentClass(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<EquipmentClass[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('equipmentClass')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as EquipmentClass[]\n }\n}\n\n@ObjectType({ description: 'A page of equipment' })\nexport class EquipmentList {\n @Field(type => [Equipment])\n items: Equipment[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(Equipment)\n@UseMiddleware(SpeakRefusals)\nexport class EquipmentResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EquipmentList, { description: 'To fetch equipment' })\n async equipmentList(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EquipmentList> {\n const { domain } = context.state\n const { items, total } = await listMaster('equipment', params, domain)\n\n return { items: items as Equipment[], total }\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [Equipment], { description: 'To create, change or retire equipment' })\n async updateMultipleEquipment(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext,\n /**\n * **언제부터 그러한가** — 배정·선언 칸을 고칠 때만 온다.\n *\n * 안 오면 지금부터다. 미래면 주장만 남고 본행은 그 시각이 올 때까지 그대로다\n * (§`claimAssignmentChanges`).\n */\n @Arg('applied', type => ScalarObject, { nullable: true }) applied?: AppliedWhen\n ): Promise<Equipment[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('equipment')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod,\n ...appliedOptions(applied)\n })\n\n return saved as Equipment[]\n }\n}\n\n@ObjectType({ description: 'A page of stop reasons' })\nexport class StopReasonList {\n @Field(type => [StopReason])\n items: StopReason[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(StopReason)\n@UseMiddleware(SpeakRefusals)\nexport class StopReasonResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => StopReasonList, { description: 'To fetch stop reasons' })\n async stopReasonList(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<StopReasonList> {\n const { domain } = context.state\n const { items, total } = await listMaster('stopReason', params, domain)\n\n return { items: items as StopReason[], total }\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [StopReason], { description: 'To create, change or retire stop reasons' })\n async updateMultipleStopReason(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<StopReason[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('stopReason')\n\n /*\n * **모르는 상태로는 저장하지 않는다.** 이 값이 가동률을 깎느냐 마느냐를 정하므로, 목록 밖 값이\n * 들어오면 그 사유를 쓴 구간이 전부 어긋남으로 걸린다 — 잘못은 여기서 났는데 불은 거기서 켜진다.\n *\n * 지우는 패치(`retire`)는 상태를 다시 말하지 않으므로 값이 있을 때만 본다.\n */\n for (const patch of patches) {\n const said = (patch as any)?.status\n if (said === undefined || said === null) continue\n\n const gap = stopReasonStatusGap(said)\n if (gap) throw new Error(`정지 사유 \"${(patch as any)?.name ?? ''}\" — ${gap}`)\n }\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as StopReason[]\n }\n}\n"]}
@@ -34,6 +34,10 @@ export * from './location/location-master';
34
34
  export * from './location/location-query';
35
35
  export * from './material/material-class';
36
36
  export * from './material/material-definition';
37
+ export * from './material/material-revision';
38
+ export * from './material/material-revision-service';
39
+ export * from './material/material-revision-resolver';
40
+ export * from './material/material-effective-list';
37
41
  export * from './material/material-master';
38
42
  export * from './material/material-query';
39
43
  export * from './operation/operation-definition';
@@ -42,6 +46,12 @@ export * from './operation/operation-query';
42
46
  export * from './operation/operation-readiness';
43
47
  export * from './operation/operation-readiness-resolver';
44
48
  export * from './recipe/recipe-definition';
49
+ export * from './recipe/recipe-revision';
50
+ export * from './recipe/recipe-revision-line';
51
+ export * from './recipe/recipe-revision-content';
52
+ export * from './recipe/recipe-revision-service';
53
+ export * from './recipe/recipe-revision-resolver';
54
+ export * from './recipe/recipe-effective-list';
45
55
  export * from './recipe/route-definition';
46
56
  export * from './recipe/recipe-master';
47
57
  export * from './recipe/recipe-query';
@@ -57,7 +67,10 @@ export * from './status/master-status';
57
67
  export * from './quality/nonconformance-cause';
58
68
  import { MasterConformanceResolver } from './master-conformance-resolver';
59
69
  import { MasterChangePolicy, MasterChangePolicyResolver } from './master-change-policy';
60
- export declare const entities: (typeof import("./equipment/equipment").Equipment | typeof import("./equipment/equipment-class").EquipmentClass | typeof import("./quality/nonconformance-cause").NonconformanceCause | typeof import("./material/material-definition").MaterialDefinition | typeof import("./operation/operation-definition").OperationDefinition | typeof import("./location/operational-location").OperationalLocation | typeof import("./personnel/person").Person | typeof import("./asset/physical-asset").PhysicalAsset | typeof import("./recipe").RecipeDefinition | typeof import("./recipe").RouteDefinition | typeof import("./test-spec/test-specification").TestSpecification | typeof MasterChangePolicy | typeof import("./test-spec/test-spec-revision").TestSpecificationRevision | typeof import("./test-spec/test-spec-revision").TestSpecificationPlan | typeof import("./test-spec/test-spec-revision").TestSpecificationSegment | typeof import("./test-spec/test-spec-revision").TestSpecificationBasis)[];
70
+ export declare const entities: (typeof import("./equipment/equipment").Equipment | typeof import("./equipment/equipment-class").EquipmentClass | typeof import("./quality/nonconformance-cause").NonconformanceCause | typeof import("./material/material-definition").MaterialDefinition | typeof import("./operation/operation-definition").OperationDefinition | typeof import("./location/operational-location").OperationalLocation | typeof import("./personnel/person").Person | typeof import("./asset/physical-asset").PhysicalAsset | typeof import("./recipe").RecipeDefinition | typeof import("./recipe").RouteDefinition | typeof import("./test-spec/test-specification").TestSpecification | typeof MasterChangePolicy | typeof import("./recipe/recipe-revision-line").RecipeRevisionOutput | typeof import("./recipe/recipe-revision").RecipeRevision | typeof import("./recipe/recipe-revision").RecipePlan | typeof import("./recipe/recipe-revision").RecipeSegment | typeof import("./recipe/recipe-revision").RecipeBasis | typeof import("./material/material-revision").MaterialDefinitionRevision | typeof import("./material/material-revision").MaterialDefinitionPlan | typeof import("./material/material-revision").MaterialDefinitionSegment | typeof import("./material/material-revision").MaterialDefinitionBasis | typeof import("./test-spec/test-spec-revision").TestSpecificationRevision | typeof import("./test-spec/test-spec-revision").TestSpecificationPlan | typeof import("./test-spec/test-spec-revision").TestSpecificationSegment | typeof import("./test-spec/test-spec-revision").TestSpecificationBasis)[];
61
71
  export declare const schema: {
62
- resolverClasses: (typeof MasterChangePolicyResolver | typeof import("./personnel/personnel-master-resolver").PersonnelClassResolver | typeof import("./personnel/personnel-master-resolver").PersonResolver | typeof import("./equipment/equipment-master-resolver").EquipmentClassResolver | typeof import("./equipment/equipment-master-resolver").EquipmentResolver | typeof import("./equipment/equipment-master-resolver").StopReasonResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetClassResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetResolver | typeof import("./material/material-master-resolver").MaterialClassResolver | typeof import("./material/material-master-resolver").MaterialDefinitionResolver | typeof import("./location/location-master-resolver").OperationalLocationResolver | typeof import("./operation/operation-master-resolver").OperationDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RecipeDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RouteDefinitionResolver | typeof import("./test-spec/test-spec-master-resolver").TestSpecificationResolver | typeof MasterConformanceResolver | typeof import("./personnel/personnel-query").PersonnelQuery | typeof import("./equipment/equipment-query").EquipmentQuery | typeof import("./asset/asset-query").AssetQuery | typeof import("./location/location-query").LocationQuery | typeof import("./material/material-query").MaterialQuery | typeof import("./operation/operation-query").OperationQuery | typeof import("./operation/operation-readiness-resolver").OperationReadinessResolver | typeof import("./recipe/recipe-query").RecipeQuery | typeof import("./test-spec/test-spec-revision-resolver").TestSpecificationRevisionResolver | typeof import("./test-spec/test-spec-query").TestSpecificationQuery | typeof import("./status/master-status").OpsMasterStatusQuery | typeof import("./equipment/stop-reason-query").StopReasonQuery | typeof import("./quality/nonconformance-cause-resolver").NonconformanceCauseResolver)[];
72
+ resolverClasses: (typeof MasterChangePolicyResolver | typeof import("./personnel/personnel-master-resolver").PersonnelClassResolver | typeof import("./personnel/personnel-master-resolver").PersonResolver | typeof import("./equipment/equipment-master-resolver").EquipmentClassResolver | typeof import("./equipment/equipment-master-resolver").EquipmentResolver | typeof import("./equipment/equipment-master-resolver").StopReasonResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetClassResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetResolver | typeof import("./material/material-master-resolver").MaterialClassResolver | typeof import("./material/material-master-resolver").MaterialDefinitionResolver | typeof import("./location/location-master-resolver").OperationalLocationResolver | typeof import("./operation/operation-master-resolver").OperationDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RecipeDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RouteDefinitionResolver | typeof import("./test-spec/test-spec-master-resolver").TestSpecificationResolver | typeof MasterConformanceResolver | typeof import("./personnel/personnel-query").PersonnelQuery | typeof import("./equipment/equipment-query").EquipmentQuery | typeof import("./asset/asset-query").AssetQuery | typeof import("./location/location-query").LocationQuery | typeof import("./material/material-revision-resolver").MaterialDefinitionRevisionResolver | typeof import("./material/material-query").MaterialQuery | typeof import("./operation/operation-query").OperationQuery | typeof import("./operation/operation-readiness-resolver").OperationReadinessResolver | typeof import("./recipe/recipe-revision-resolver").RecipeRevisionResolver | typeof import("./recipe/recipe-query").RecipeQuery | typeof import("./test-spec/test-spec-revision-resolver").TestSpecificationRevisionResolver | typeof import("./test-spec/test-spec-query").TestSpecificationQuery | typeof import("./status/master-status").OpsMasterStatusQuery | typeof import("./equipment/stop-reason-query").StopReasonQuery | typeof import("./quality/nonconformance-cause-resolver").NonconformanceCauseResolver)[];
63
73
  };
74
+ export * from './assignment/assignment-claim';
75
+ export * from './assignment/assignment-history';
76
+ export * from './assignment/assignment-write';