@things-factory/station 10.1.33
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/README.md +124 -0
- package/dist-client/index.d.ts +11 -0
- package/dist-client/index.js +13 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/station/scene/index.d.ts +11 -0
- package/dist-client/station/scene/index.js +12 -0
- package/dist-client/station/scene/index.js.map +1 -0
- package/dist-client/station/scene/station-context-binding.d.ts +25 -0
- package/dist-client/station/scene/station-context-binding.js +39 -0
- package/dist-client/station/scene/station-context-binding.js.map +1 -0
- package/dist-client/station/scene/station-context-scene.d.ts +28 -0
- package/dist-client/station/scene/station-context-scene.js +138 -0
- package/dist-client/station/scene/station-context-scene.js.map +1 -0
- package/dist-client/station/scene/station-counts-scene.d.ts +6 -0
- package/dist-client/station/scene/station-counts-scene.js +51 -0
- package/dist-client/station/scene/station-counts-scene.js.map +1 -0
- package/dist-client/station/scene/station-field-scene.d.ts +6 -0
- package/dist-client/station/scene/station-field-scene.js +89 -0
- package/dist-client/station/scene/station-field-scene.js.map +1 -0
- package/dist-client/station/scene/station-icons.d.ts +82 -0
- package/dist-client/station/scene/station-icons.js +131 -0
- package/dist-client/station/scene/station-icons.js.map +1 -0
- package/dist-client/station/scene/station-numpad-scene.d.ts +9 -0
- package/dist-client/station/scene/station-numpad-scene.js +144 -0
- package/dist-client/station/scene/station-numpad-scene.js.map +1 -0
- package/dist-client/station/scene/station-scene-style.d.ts +51 -0
- package/dist-client/station/scene/station-scene-style.js +108 -0
- package/dist-client/station/scene/station-scene-style.js.map +1 -0
- package/dist-client/station/scene/station-scene.d.ts +295 -0
- package/dist-client/station/scene/station-scene.js +68 -0
- package/dist-client/station/scene/station-scene.js.map +1 -0
- package/dist-client/station/scene/station-who-scene.d.ts +6 -0
- package/dist-client/station/scene/station-who-scene.js +48 -0
- package/dist-client/station/scene/station-who-scene.js.map +1 -0
- package/dist-client/station/scene/station-work-panel-scene.d.ts +28 -0
- package/dist-client/station/scene/station-work-panel-scene.js +37 -0
- package/dist-client/station/scene/station-work-panel-scene.js.map +1 -0
- package/dist-client/station/station-board-binding.d.ts +16 -0
- package/dist-client/station/station-board-binding.js +20 -0
- package/dist-client/station/station-board-binding.js.map +1 -0
- package/dist-client/station/station-context.d.ts +178 -0
- package/dist-client/station/station-context.js +30 -0
- package/dist-client/station/station-context.js.map +1 -0
- package/dist-client/station/station-palette.d.ts +34 -0
- package/dist-client/station/station-palette.js +119 -0
- package/dist-client/station/station-palette.js.map +1 -0
- package/dist-client/station/station-runtime.d.ts +47 -0
- package/dist-client/station/station-runtime.js +47 -0
- package/dist-client/station/station-runtime.js.map +1 -0
- package/dist-client/station/station-scene-context.d.ts +68 -0
- package/dist-client/station/station-scene-context.js +62 -0
- package/dist-client/station/station-scene-context.js.map +1 -0
- package/dist-client/station/station-screen-flow.d.ts +16 -0
- package/dist-client/station/station-screen-flow.js +58 -0
- package/dist-client/station/station-screen-flow.js.map +1 -0
- package/dist-client/station/station-tile-registry.d.ts +89 -0
- package/dist-client/station/station-tile-registry.js +86 -0
- package/dist-client/station/station-tile-registry.js.map +1 -0
- package/dist-client/station/station-work-panel-view.d.ts +23 -0
- package/dist-client/station/station-work-panel-view.js +125 -0
- package/dist-client/station/station-work-panel-view.js.map +1 -0
- package/dist-client/station/station-work-runtime.d.ts +47 -0
- package/dist-client/station/station-work-runtime.js +161 -0
- package/dist-client/station/station-work-runtime.js.map +1 -0
- package/dist-client/station/station-work-scenarios.d.ts +41 -0
- package/dist-client/station/station-work-scenarios.js +59 -0
- package/dist-client/station/station-work-scenarios.js.map +1 -0
- package/dist-client/station/task-counts.d.ts +32 -0
- package/dist-client/station/task-counts.js +26 -0
- package/dist-client/station/task-counts.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-server/activities/activity-station-screen-control-withdrawal.d.ts +62 -0
- package/dist-server/activities/activity-station-screen-control-withdrawal.js +147 -0
- package/dist-server/activities/activity-station-screen-control-withdrawal.js.map +1 -0
- package/dist-server/activities/activity-station-screen-release.d.ts +81 -0
- package/dist-server/activities/activity-station-screen-release.js +147 -0
- package/dist-server/activities/activity-station-screen-release.js.map +1 -0
- package/dist-server/activities/index.d.ts +49 -0
- package/dist-server/activities/index.js +21 -0
- package/dist-server/activities/index.js.map +1 -0
- package/dist-server/index.d.ts +3 -0
- package/dist-server/index.js +8 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/service/index.d.ts +23 -0
- package/dist-server/service/index.js +41 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/station/deletion-changes.d.ts +14 -0
- package/dist-server/service/station/deletion-changes.js +25 -0
- package/dist-server/service/station/deletion-changes.js.map +1 -0
- package/dist-server/service/station/index.d.ts +13 -0
- package/dist-server/service/station/index.js +25 -0
- package/dist-server/service/station/index.js.map +1 -0
- package/dist-server/service/station/reversibility.d.ts +21 -0
- package/dist-server/service/station/reversibility.js +24 -0
- package/dist-server/service/station/reversibility.js.map +1 -0
- package/dist-server/service/station/screen-model-digest.d.ts +60 -0
- package/dist-server/service/station/screen-model-digest.js +97 -0
- package/dist-server/service/station/screen-model-digest.js.map +1 -0
- package/dist-server/service/station/staged-material.d.ts +62 -0
- package/dist-server/service/station/staged-material.js +44 -0
- package/dist-server/service/station/staged-material.js.map +1 -0
- package/dist-server/service/station/station-argument-sources.d.ts +31 -0
- package/dist-server/service/station/station-argument-sources.js +66 -0
- package/dist-server/service/station/station-argument-sources.js.map +1 -0
- package/dist-server/service/station/station-assignment-choice.d.ts +81 -0
- package/dist-server/service/station/station-assignment-choice.js +105 -0
- package/dist-server/service/station/station-assignment-choice.js.map +1 -0
- package/dist-server/service/station/station-assignment-resolver.d.ts +104 -0
- package/dist-server/service/station/station-assignment-resolver.js +426 -0
- package/dist-server/service/station/station-assignment-resolver.js.map +1 -0
- package/dist-server/service/station/station-assignment-service.d.ts +33 -0
- package/dist-server/service/station/station-assignment-service.js +64 -0
- package/dist-server/service/station/station-assignment-service.js.map +1 -0
- package/dist-server/service/station/station-axes.d.ts +9 -0
- package/dist-server/service/station/station-axes.js +16 -0
- package/dist-server/service/station/station-axes.js.map +1 -0
- package/dist-server/service/station/station-flow.d.ts +156 -0
- package/dist-server/service/station/station-flow.js +255 -0
- package/dist-server/service/station/station-flow.js.map +1 -0
- package/dist-server/service/station/station-generate.d.ts +76 -0
- package/dist-server/service/station/station-generate.js +178 -0
- package/dist-server/service/station/station-generate.js.map +1 -0
- package/dist-server/service/station/station-product.d.ts +123 -0
- package/dist-server/service/station/station-product.js +77 -0
- package/dist-server/service/station/station-product.js.map +1 -0
- package/dist-server/service/station/station-runtime-binding.d.ts +6 -0
- package/dist-server/service/station/station-runtime-binding.js +46 -0
- package/dist-server/service/station/station-runtime-binding.js.map +1 -0
- package/dist-server/service/station/station-screen-assignment.d.ts +94 -0
- package/dist-server/service/station/station-screen-assignment.js +154 -0
- package/dist-server/service/station/station-screen-assignment.js.map +1 -0
- package/dist-server/service/station/station-screen-control-withdrawal-resolver.d.ts +37 -0
- package/dist-server/service/station/station-screen-control-withdrawal-resolver.js +130 -0
- package/dist-server/service/station/station-screen-control-withdrawal-resolver.js.map +1 -0
- package/dist-server/service/station/station-screen-control-withdrawal.d.ts +104 -0
- package/dist-server/service/station/station-screen-control-withdrawal.js +128 -0
- package/dist-server/service/station/station-screen-control-withdrawal.js.map +1 -0
- package/dist-server/service/station/station-screen-draft-resolver.d.ts +47 -0
- package/dist-server/service/station/station-screen-draft-resolver.js +153 -0
- package/dist-server/service/station/station-screen-draft-resolver.js.map +1 -0
- package/dist-server/service/station/station-screen-layout.d.ts +119 -0
- package/dist-server/service/station/station-screen-layout.js +202 -0
- package/dist-server/service/station/station-screen-layout.js.map +1 -0
- package/dist-server/service/station/station-screen-list-resolver.d.ts +69 -0
- package/dist-server/service/station/station-screen-list-resolver.js +215 -0
- package/dist-server/service/station/station-screen-list-resolver.js.map +1 -0
- package/dist-server/service/station/station-screen-publish-subscriber.d.ts +22 -0
- package/dist-server/service/station/station-screen-publish-subscriber.js +90 -0
- package/dist-server/service/station/station-screen-publish-subscriber.js.map +1 -0
- package/dist-server/service/station/station-screen-release-gate.d.ts +66 -0
- package/dist-server/service/station/station-screen-release-gate.js +67 -0
- package/dist-server/service/station/station-screen-release-gate.js.map +1 -0
- package/dist-server/service/station/station-screen-release-record.d.ts +62 -0
- package/dist-server/service/station/station-screen-release-record.js +139 -0
- package/dist-server/service/station/station-screen-release-record.js.map +1 -0
- package/dist-server/service/station/station-screen-release-signature.d.ts +23 -0
- package/dist-server/service/station/station-screen-release-signature.js +32 -0
- package/dist-server/service/station/station-screen-release-signature.js.map +1 -0
- package/dist-server/service/station/station-screen-scorecard.d.ts +15 -0
- package/dist-server/service/station/station-screen-scorecard.js +35 -0
- package/dist-server/service/station/station-screen-scorecard.js.map +1 -0
- package/dist-server/service/station/station-screen-spec-resolver.d.ts +36 -0
- package/dist-server/service/station/station-screen-spec-resolver.js +202 -0
- package/dist-server/service/station/station-screen-spec-resolver.js.map +1 -0
- package/dist-server/service/station/station-screen-spec.d.ts +104 -0
- package/dist-server/service/station/station-screen-spec.js +114 -0
- package/dist-server/service/station/station-screen-spec.js.map +1 -0
- package/dist-server/service/station/station-screen-thumbnail.d.ts +11 -0
- package/dist-server/service/station/station-screen-thumbnail.js +36 -0
- package/dist-server/service/station/station-screen-thumbnail.js.map +1 -0
- package/dist-server/service/station/station-service-resolver.d.ts +27 -0
- package/dist-server/service/station/station-service-resolver.js +95 -0
- package/dist-server/service/station/station-service-resolver.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +44 -0
- package/shared/station-axes.d.ts +4 -0
- package/shared/station-axes.js +155 -0
- package/shared/station-screen-flow-check.d.ts +12 -0
- package/shared/station-screen-flow-check.js +74 -0
- package/things-scene.config.js +15 -0
- package/translations/en.json +42 -0
- package/translations/ja.json +42 -0
- package/translations/ko.json +42 -0
- package/translations/ms.json +42 -0
- package/translations/zh.json +42 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Domain } from '@things-factory/shell';
|
|
2
|
+
import { User } from '@things-factory/auth-base';
|
|
3
|
+
/**
|
|
4
|
+
* Which screen a station gets — **the assignment, not the drawing.**
|
|
5
|
+
*
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
7
|
+
* ── What could not be said ─────────────────────────────────────────────────
|
|
8
|
+
* A board reached a station only through its address: someone typed `?board=<id>` into a tablet and
|
|
9
|
+
* that tablet showed that board until someone typed a different one. So "the press stations get the
|
|
10
|
+
* new layout" was a walk around the factory, and "welders see the qualification screen" could not be
|
|
11
|
+
* expressed at all.
|
|
12
|
+
*
|
|
13
|
+
* ── Why it lives here and not in board-service ─────────────────────────────
|
|
14
|
+
* The axes are this product's words — operation, route, material class, personnel class. Teaching
|
|
15
|
+
* the board service to know them would put manufacturing vocabulary in a package that draws
|
|
16
|
+
* rectangles, and every other consumer of boards would inherit it.
|
|
17
|
+
*
|
|
18
|
+
* ── The axes are the ones the context already carries ──────────────────────
|
|
19
|
+
* Deliberately the same five. One vocabulary answers both "what does this screen show" and "which
|
|
20
|
+
* screen shows" — if they drifted apart, a factory could select on something a screen cannot display
|
|
21
|
+
* and never understand why the board is blank.
|
|
22
|
+
*
|
|
23
|
+
* ── Absent means any ───────────────────────────────────────────────────────
|
|
24
|
+
* Every axis is nullable and an empty one is not a constraint. That is what makes one row able to
|
|
25
|
+
* say "every press" and another "this machine, this operation" without two kinds of assignment.
|
|
26
|
+
* How they compete is `station-screen-choice.ts`, kept pure so the rule can be argued about without
|
|
27
|
+
* a database.
|
|
28
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
29
|
+
*/
|
|
30
|
+
export declare class StationScreenAssignment {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
domain?: Domain;
|
|
33
|
+
domainId?: string;
|
|
34
|
+
/** What this assignment is called. It is what the answer names when it says which screen won. */
|
|
35
|
+
name: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
/**
|
|
38
|
+
* The drawing to put on this station — a board, by id.
|
|
39
|
+
*
|
|
40
|
+
* ── This was briefly a name pointing at our own `StationScreen` table ────────────────────
|
|
41
|
+
* That table was `Board` with different words: same columns, same release/revert/history, same
|
|
42
|
+
* verbs. What is actually ours is not the drawing but what surrounds it — which station sees
|
|
43
|
+
* which one (this table) and what the drawing needs in order to work (`StationScreenSpec`).
|
|
44
|
+
*
|
|
45
|
+
* An id and not a name, because that is what board-service is keyed by, and because a name is
|
|
46
|
+
* reusable there: `ix_board_1` is scoped to `deleted_at IS NULL`, so deleting a board frees its
|
|
47
|
+
* name for a new one. An assignment holding a name would silently follow that new board.
|
|
48
|
+
*/
|
|
49
|
+
boardId: string;
|
|
50
|
+
equipmentName?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Any machine of this class — `Equipment.equipmentClassIds` or its `kind`.
|
|
53
|
+
*
|
|
54
|
+
* This is the axis that makes assignment worth having. "Every press gets the new layout" is one
|
|
55
|
+
* row; naming the machines is a row per machine and a walk around the factory when one is added.
|
|
56
|
+
*/
|
|
57
|
+
equipmentClassId?: string;
|
|
58
|
+
/** Any station on this line — the ISA-95 `ProductionLine` the station's location sits under. */
|
|
59
|
+
workCenterName?: string;
|
|
60
|
+
operationKey?: string;
|
|
61
|
+
routeKey?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Orders making something of this class — standard `MaterialClassID`.
|
|
64
|
+
*
|
|
65
|
+
* By class and not by item on purpose: a plant has thousands of items and nobody assigns a screen
|
|
66
|
+
* to each. The class is the unit a person actually thinks in.
|
|
67
|
+
*/
|
|
68
|
+
materialClassId?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Whoever is scanned in belongs to this class — standard `PersonnelClassID`.
|
|
71
|
+
*
|
|
72
|
+
* This is how a trainee gets a different screen from a qualified operator. It only matches once
|
|
73
|
+
* somebody has scanned in — before that the station does not know who is there, and guessing would
|
|
74
|
+
* put the wrong screen in front of the wrong person.
|
|
75
|
+
*/
|
|
76
|
+
personnelClassId?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Breaks a tie between screens neither of which is more specific. Higher wins.
|
|
79
|
+
*
|
|
80
|
+
* Needed because specificity is a partial order: `{machine}` and `{line, operation}` cannot be
|
|
81
|
+
* ranked without inventing a weight, so a person writes down which one they meant.
|
|
82
|
+
*/
|
|
83
|
+
priority?: number;
|
|
84
|
+
/** From when this assignment applies — standard `EffectiveStartDate`. */
|
|
85
|
+
effectiveStart?: Date;
|
|
86
|
+
/** Until when. Lets a changeover be prepared in advance instead of switched by hand on the day. */
|
|
87
|
+
effectiveEnd?: Date;
|
|
88
|
+
createdAt?: Date;
|
|
89
|
+
updatedAt?: Date;
|
|
90
|
+
creator?: User;
|
|
91
|
+
creatorId?: string;
|
|
92
|
+
updater?: User;
|
|
93
|
+
updaterId?: string;
|
|
94
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StationScreenAssignment = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
9
|
+
/**
|
|
10
|
+
* Which screen a station gets — **the assignment, not the drawing.**
|
|
11
|
+
*
|
|
12
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
13
|
+
* ── What could not be said ─────────────────────────────────────────────────
|
|
14
|
+
* A board reached a station only through its address: someone typed `?board=<id>` into a tablet and
|
|
15
|
+
* that tablet showed that board until someone typed a different one. So "the press stations get the
|
|
16
|
+
* new layout" was a walk around the factory, and "welders see the qualification screen" could not be
|
|
17
|
+
* expressed at all.
|
|
18
|
+
*
|
|
19
|
+
* ── Why it lives here and not in board-service ─────────────────────────────
|
|
20
|
+
* The axes are this product's words — operation, route, material class, personnel class. Teaching
|
|
21
|
+
* the board service to know them would put manufacturing vocabulary in a package that draws
|
|
22
|
+
* rectangles, and every other consumer of boards would inherit it.
|
|
23
|
+
*
|
|
24
|
+
* ── The axes are the ones the context already carries ──────────────────────
|
|
25
|
+
* Deliberately the same five. One vocabulary answers both "what does this screen show" and "which
|
|
26
|
+
* screen shows" — if they drifted apart, a factory could select on something a screen cannot display
|
|
27
|
+
* and never understand why the board is blank.
|
|
28
|
+
*
|
|
29
|
+
* ── Absent means any ───────────────────────────────────────────────────────
|
|
30
|
+
* Every axis is nullable and an empty one is not a constraint. That is what makes one row able to
|
|
31
|
+
* say "every press" and another "this machine, this operation" without two kinds of assignment.
|
|
32
|
+
* How they compete is `station-screen-choice.ts`, kept pure so the rule can be argued about without
|
|
33
|
+
* a database.
|
|
34
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
35
|
+
*/
|
|
36
|
+
let StationScreenAssignment = class StationScreenAssignment {
|
|
37
|
+
};
|
|
38
|
+
exports.StationScreenAssignment = StationScreenAssignment;
|
|
39
|
+
tslib_1.__decorate([
|
|
40
|
+
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
|
41
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.ID),
|
|
42
|
+
tslib_1.__metadata("design:type", String)
|
|
43
|
+
], StationScreenAssignment.prototype, "id", void 0);
|
|
44
|
+
tslib_1.__decorate([
|
|
45
|
+
(0, typeorm_1.ManyToOne)(type => shell_1.Domain),
|
|
46
|
+
(0, type_graphql_1.Field)(type => shell_1.Domain),
|
|
47
|
+
tslib_1.__metadata("design:type", shell_1.Domain)
|
|
48
|
+
], StationScreenAssignment.prototype, "domain", void 0);
|
|
49
|
+
tslib_1.__decorate([
|
|
50
|
+
(0, typeorm_1.RelationId)((assignment) => assignment.domain),
|
|
51
|
+
tslib_1.__metadata("design:type", String)
|
|
52
|
+
], StationScreenAssignment.prototype, "domainId", void 0);
|
|
53
|
+
tslib_1.__decorate([
|
|
54
|
+
(0, typeorm_1.Column)(),
|
|
55
|
+
(0, type_graphql_1.Field)(),
|
|
56
|
+
tslib_1.__metadata("design:type", String)
|
|
57
|
+
], StationScreenAssignment.prototype, "name", void 0);
|
|
58
|
+
tslib_1.__decorate([
|
|
59
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
60
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
61
|
+
tslib_1.__metadata("design:type", String)
|
|
62
|
+
], StationScreenAssignment.prototype, "description", void 0);
|
|
63
|
+
tslib_1.__decorate([
|
|
64
|
+
(0, typeorm_1.Column)(),
|
|
65
|
+
(0, type_graphql_1.Field)({ description: "the board to draw — the board's id in board-service" }),
|
|
66
|
+
tslib_1.__metadata("design:type", String)
|
|
67
|
+
], StationScreenAssignment.prototype, "boardId", void 0);
|
|
68
|
+
tslib_1.__decorate([
|
|
69
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
70
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'this one machine' }),
|
|
71
|
+
tslib_1.__metadata("design:type", String)
|
|
72
|
+
], StationScreenAssignment.prototype, "equipmentName", void 0);
|
|
73
|
+
tslib_1.__decorate([
|
|
74
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
75
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'any machine belonging to this EquipmentClassID' }),
|
|
76
|
+
tslib_1.__metadata("design:type", String)
|
|
77
|
+
], StationScreenAssignment.prototype, "equipmentClassId", void 0);
|
|
78
|
+
tslib_1.__decorate([
|
|
79
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
80
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
81
|
+
tslib_1.__metadata("design:type", String)
|
|
82
|
+
], StationScreenAssignment.prototype, "workCenterName", void 0);
|
|
83
|
+
tslib_1.__decorate([
|
|
84
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
85
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'stations performing this operation' }),
|
|
86
|
+
tslib_1.__metadata("design:type", String)
|
|
87
|
+
], StationScreenAssignment.prototype, "operationKey", void 0);
|
|
88
|
+
tslib_1.__decorate([
|
|
89
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
90
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'orders running this route' }),
|
|
91
|
+
tslib_1.__metadata("design:type", String)
|
|
92
|
+
], StationScreenAssignment.prototype, "routeKey", void 0);
|
|
93
|
+
tslib_1.__decorate([
|
|
94
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
95
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'orders for material of this MaterialClassID' }),
|
|
96
|
+
tslib_1.__metadata("design:type", String)
|
|
97
|
+
], StationScreenAssignment.prototype, "materialClassId", void 0);
|
|
98
|
+
tslib_1.__decorate([
|
|
99
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
100
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'whoever is scanned in belongs to this PersonnelClassID' }),
|
|
101
|
+
tslib_1.__metadata("design:type", String)
|
|
102
|
+
], StationScreenAssignment.prototype, "personnelClassId", void 0);
|
|
103
|
+
tslib_1.__decorate([
|
|
104
|
+
(0, typeorm_1.Column)({ type: 'int', nullable: true }),
|
|
105
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'higher wins when neither screen is more specific' }),
|
|
106
|
+
tslib_1.__metadata("design:type", Number)
|
|
107
|
+
], StationScreenAssignment.prototype, "priority", void 0);
|
|
108
|
+
tslib_1.__decorate([
|
|
109
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
110
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
111
|
+
tslib_1.__metadata("design:type", Date
|
|
112
|
+
/** Until when. Lets a changeover be prepared in advance instead of switched by hand on the day. */
|
|
113
|
+
)
|
|
114
|
+
], StationScreenAssignment.prototype, "effectiveStart", void 0);
|
|
115
|
+
tslib_1.__decorate([
|
|
116
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
117
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
118
|
+
tslib_1.__metadata("design:type", Date)
|
|
119
|
+
], StationScreenAssignment.prototype, "effectiveEnd", void 0);
|
|
120
|
+
tslib_1.__decorate([
|
|
121
|
+
(0, typeorm_1.CreateDateColumn)(),
|
|
122
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
123
|
+
tslib_1.__metadata("design:type", Date)
|
|
124
|
+
], StationScreenAssignment.prototype, "createdAt", void 0);
|
|
125
|
+
tslib_1.__decorate([
|
|
126
|
+
(0, typeorm_1.UpdateDateColumn)(),
|
|
127
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
128
|
+
tslib_1.__metadata("design:type", Date)
|
|
129
|
+
], StationScreenAssignment.prototype, "updatedAt", void 0);
|
|
130
|
+
tslib_1.__decorate([
|
|
131
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
132
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
|
|
133
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
134
|
+
], StationScreenAssignment.prototype, "creator", void 0);
|
|
135
|
+
tslib_1.__decorate([
|
|
136
|
+
(0, typeorm_1.RelationId)((assignment) => assignment.creator),
|
|
137
|
+
tslib_1.__metadata("design:type", String)
|
|
138
|
+
], StationScreenAssignment.prototype, "creatorId", void 0);
|
|
139
|
+
tslib_1.__decorate([
|
|
140
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
141
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
|
|
142
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
143
|
+
], StationScreenAssignment.prototype, "updater", void 0);
|
|
144
|
+
tslib_1.__decorate([
|
|
145
|
+
(0, typeorm_1.RelationId)((assignment) => assignment.updater),
|
|
146
|
+
tslib_1.__metadata("design:type", String)
|
|
147
|
+
], StationScreenAssignment.prototype, "updaterId", void 0);
|
|
148
|
+
exports.StationScreenAssignment = StationScreenAssignment = tslib_1.__decorate([
|
|
149
|
+
(0, typeorm_1.Entity)(),
|
|
150
|
+
(0, typeorm_1.Index)('ix_mes_station_screen_assignment_0', (assignment) => [assignment.domain, assignment.name], { unique: true }),
|
|
151
|
+
(0, typeorm_1.Index)('ix_mes_station_screen_assignment_1', (assignment) => [assignment.domain, assignment.equipmentName]),
|
|
152
|
+
(0, type_graphql_1.ObjectType)({ description: 'Which screen a station shows, and when' })
|
|
153
|
+
], StationScreenAssignment);
|
|
154
|
+
//# sourceMappingURL=station-screen-assignment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"station-screen-assignment.js","sourceRoot":"","sources":["../../../server/service/station/station-screen-assignment.ts"],"names":[],"mappings":"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","sourcesContent":["import { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, UpdateDateColumn } from 'typeorm'\nimport { Field, ID, Int, ObjectType } from 'type-graphql'\n\nimport { Domain } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\n/**\n * Which screen a station gets — **the assignment, not the drawing.**\n *\n * ═══════════════════════════════════════════════════════════════════════════\n * ── What could not be said ─────────────────────────────────────────────────\n * A board reached a station only through its address: someone typed `?board=<id>` into a tablet and\n * that tablet showed that board until someone typed a different one. So \"the press stations get the\n * new layout\" was a walk around the factory, and \"welders see the qualification screen\" could not be\n * expressed at all.\n *\n * ── Why it lives here and not in board-service ─────────────────────────────\n * The axes are this product's words — operation, route, material class, personnel class. Teaching\n * the board service to know them would put manufacturing vocabulary in a package that draws\n * rectangles, and every other consumer of boards would inherit it.\n *\n * ── The axes are the ones the context already carries ──────────────────────\n * Deliberately the same five. One vocabulary answers both \"what does this screen show\" and \"which\n * screen shows\" — if they drifted apart, a factory could select on something a screen cannot display\n * and never understand why the board is blank.\n *\n * ── Absent means any ───────────────────────────────────────────────────────\n * Every axis is nullable and an empty one is not a constraint. That is what makes one row able to\n * say \"every press\" and another \"this machine, this operation\" without two kinds of assignment.\n * How they compete is `station-screen-choice.ts`, kept pure so the rule can be argued about without\n * a database.\n * ═══════════════════════════════════════════════════════════════════════════\n */\n@Entity()\n@Index('ix_mes_station_screen_assignment_0', (assignment: StationScreenAssignment) => [assignment.domain, assignment.name], { unique: true })\n@Index('ix_mes_station_screen_assignment_1', (assignment: StationScreenAssignment) => [assignment.domain, assignment.equipmentName])\n@ObjectType({ description: 'Which screen a station shows, and when' })\nexport class StationScreenAssignment {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain)\n domain?: Domain\n\n @RelationId((assignment: StationScreenAssignment) => assignment.domain)\n domainId?: string\n\n /** What this assignment is called. It is what the answer names when it says which screen won. */\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n /**\n * The drawing to put on this station — a board, by id.\n *\n * ── This was briefly a name pointing at our own `StationScreen` table ────────────────────\n * That table was `Board` with different words: same columns, same release/revert/history, same\n * verbs. What is actually ours is not the drawing but what surrounds it — which station sees\n * which one (this table) and what the drawing needs in order to work (`StationScreenSpec`).\n *\n * An id and not a name, because that is what board-service is keyed by, and because a name is\n * reusable there: `ix_board_1` is scoped to `deleted_at IS NULL`, so deleting a board frees its\n * name for a new one. An assignment holding a name would silently follow that new board.\n */\n @Column()\n @Field({ description: \"the board to draw — the board's id in board-service\" })\n boardId: string\n\n /*\n * ── 판은 배정이 고르지 않는다 ────────────────────────────────────────────\n * `screenVersion` 으로 특정 판에 못 박을 수 있게 두었다가 걷었다.\n *\n * 현장 관리자가 축 일곱 개를 채우고 거기에 「어느 판」까지 고르는 일은 실제로 안 일어나고, 한 번\n * 박으면 **아무도 안 푼다** — 그 라인만 몇 달째 옛 화면을 보는데 관리 화면은 초록이다. 실제로 그\n * 결함이 이미 있었다: 없는 판에 박아도 `usable` 로 섰다.\n *\n * 새 판을 한 라인에서 먼저 돌려 보는 것도 이걸로 할 일이 아니다. 깨지면 되돌리기는 화면 쪽에서\n * `RELEASED` 를 뒤집는 것이고, 라인마다 다른 것을 그려야 한다면 그것은 다른 화면이다(이름을 따로\n * 준다). 같은 이름이 자리마다 다른 것을 그리면 나중에 「그때 무엇을 봤나」에 아무도 답 못 한다.\n *\n * **어느 화면인가는 배정이, 어느 판인가는 화면이 정한다.**\n */\n\n /* ── The axes. Empty is not a constraint. ─────────────────────────────── */\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'this one machine' })\n equipmentName?: string\n\n /**\n * Any machine of this class — `Equipment.equipmentClassIds` or its `kind`.\n *\n * This is the axis that makes assignment worth having. \"Every press gets the new layout\" is one\n * row; naming the machines is a row per machine and a walk around the factory when one is added.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'any machine belonging to this EquipmentClassID' })\n equipmentClassId?: string\n\n /** Any station on this line — the ISA-95 `ProductionLine` the station's location sits under. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n workCenterName?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'stations performing this operation' })\n operationKey?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'orders running this route' })\n routeKey?: string\n\n /**\n * Orders making something of this class — standard `MaterialClassID`.\n *\n * By class and not by item on purpose: a plant has thousands of items and nobody assigns a screen\n * to each. The class is the unit a person actually thinks in.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'orders for material of this MaterialClassID' })\n materialClassId?: string\n\n /**\n * Whoever is scanned in belongs to this class — standard `PersonnelClassID`.\n *\n * This is how a trainee gets a different screen from a qualified operator. It only matches once\n * somebody has scanned in — before that the station does not know who is there, and guessing would\n * put the wrong screen in front of the wrong person.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'whoever is scanned in belongs to this PersonnelClassID' })\n personnelClassId?: string\n\n /**\n * Breaks a tie between screens neither of which is more specific. Higher wins.\n *\n * Needed because specificity is a partial order: `{machine}` and `{line, operation}` cannot be\n * ranked without inventing a weight, so a person writes down which one they meant.\n */\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'higher wins when neither screen is more specific' })\n priority?: number\n\n /** From when this assignment applies — standard `EffectiveStartDate`. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveStart?: Date\n\n /** Until when. Lets a changeover be prepared in advance instead of switched by hand on the day. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveEnd?: Date\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((assignment: StationScreenAssignment) => assignment.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((assignment: StationScreenAssignment) => assignment.updater)\n updaterId?: string\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ApprovalLineStanding } from '@things-factory/worklist';
|
|
2
|
+
/**
|
|
3
|
+
* **통제를 켜고 끄는 결재선** — 화면 발행 승인의 결재선 하나다.
|
|
4
|
+
*
|
|
5
|
+
* 켤 때(`saveStationScreenSpec`)와 끌 때(`requestStationScreenControlWithdrawal`)가 **같은 함수로**
|
|
6
|
+
* 판정한다. 둘이 따로 읽으면, 켤 수는 없는데 끌 수는 있는(또는 그 반대의) 공장이 생긴다.
|
|
7
|
+
*/
|
|
8
|
+
export declare function controlLineStanding(context: ResolverContext): Promise<{
|
|
9
|
+
activity?: {
|
|
10
|
+
id?: string;
|
|
11
|
+
approvalLine?: unknown[];
|
|
12
|
+
};
|
|
13
|
+
standing: ApprovalLineStanding;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* 통제 문서를 **통제 밖으로 내보내자고 결재에 올린다.**
|
|
17
|
+
*
|
|
18
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
19
|
+
* ── 올리기만 한다. spec 은 그대로다 ────────────────────────────────────────
|
|
20
|
+
* 승인 전까지 이 화면은 여전히 통제 문서이고, 서명 없는 판은 그동안에도 발행 관문에서 거절된다
|
|
21
|
+
* (아키텍트 조건 ①). 여기서 spec 을 쓰면 「올렸다」가 곧 「껐다」가 된다 — 이 파일에는 spec 을
|
|
22
|
+
* 쓰는 줄이 없어야 한다(`station-screen-control-withdrawal.test.ts` 가 센다).
|
|
23
|
+
*
|
|
24
|
+
* ── 무엇을 거둘지는 올릴 때 굳힌다 ─────────────────────────────────────────
|
|
25
|
+
* spec 의 **id** 와 방식(끄기 · 지우기)을 싣는다. 승인 콜백은 그것만 한다(조건 ②).
|
|
26
|
+
*
|
|
27
|
+
* ── 결재선은 발행 승인의 것을 **올리는 순간** 읽어 싣는다 ─────────────────
|
|
28
|
+
* 이 문 자신의 결재선 칸은 쓰지 않는다. 같은 결재선을 값으로 두 번 두면 갈린다.
|
|
29
|
+
*
|
|
30
|
+
* ── 이 문을 여는 자리 ─────────────────────────────────────────────────────
|
|
31
|
+
* 화면을 만드는 권한(`station:mutation`)을 든 자리가 올리고, 발행 승인의 결재선(품질)이 정한다 —
|
|
32
|
+
* 작성자는 승인하지 않는다(ADR-0047 ⑦).
|
|
33
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
34
|
+
*/
|
|
35
|
+
export declare class StationScreenControlWithdrawalResolver {
|
|
36
|
+
requestStationScreenControlWithdrawal(boardId: string, reason: string, remove: boolean | undefined, context: ResolverContext): Promise<string>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StationScreenControlWithdrawalResolver = void 0;
|
|
4
|
+
exports.controlLineStanding = controlLineStanding;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const typeorm_1 = require("typeorm");
|
|
8
|
+
const shell_1 = require("@things-factory/shell");
|
|
9
|
+
const board_service_1 = require("@things-factory/board-service");
|
|
10
|
+
const worklist_1 = require("@things-factory/worklist");
|
|
11
|
+
const activity_station_screen_control_withdrawal_1 = require("../../activities/activity-station-screen-control-withdrawal");
|
|
12
|
+
const activity_station_screen_release_1 = require("../../activities/activity-station-screen-release");
|
|
13
|
+
const worklist_2 = require("@things-factory/worklist");
|
|
14
|
+
const station_screen_control_withdrawal_1 = require("./station-screen-control-withdrawal");
|
|
15
|
+
const station_screen_spec_1 = require("./station-screen-spec");
|
|
16
|
+
/** 아직 끝나지 않은 상태들 — 끝난 것과 접힌 것만 뺀다(§`disposition-pending`). */
|
|
17
|
+
const OPEN_STATES = [
|
|
18
|
+
worklist_1.ActivityInstanceStatus.Draft,
|
|
19
|
+
worklist_1.ActivityInstanceStatus.Issued,
|
|
20
|
+
worklist_1.ActivityInstanceStatus.Unassigned,
|
|
21
|
+
worklist_1.ActivityInstanceStatus.Assigned,
|
|
22
|
+
worklist_1.ActivityInstanceStatus.Started,
|
|
23
|
+
worklist_1.ActivityInstanceStatus.Pending
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* **통제를 켜고 끄는 결재선** — 화면 발행 승인의 결재선 하나다.
|
|
27
|
+
*
|
|
28
|
+
* 켤 때(`saveStationScreenSpec`)와 끌 때(`requestStationScreenControlWithdrawal`)가 **같은 함수로**
|
|
29
|
+
* 판정한다. 둘이 따로 읽으면, 켤 수는 없는데 끌 수는 있는(또는 그 반대의) 공장이 생긴다.
|
|
30
|
+
*/
|
|
31
|
+
async function controlLineStanding(context) {
|
|
32
|
+
const activity = await (0, worklist_2.activityNamed)(activity_station_screen_release_1.STATION_SCREEN_RELEASE_ACTIVITY, context);
|
|
33
|
+
return { activity, standing: await (0, worklist_2.approvalLineStanding)(activity, context) };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 통제 문서를 **통제 밖으로 내보내자고 결재에 올린다.**
|
|
37
|
+
*
|
|
38
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
39
|
+
* ── 올리기만 한다. spec 은 그대로다 ────────────────────────────────────────
|
|
40
|
+
* 승인 전까지 이 화면은 여전히 통제 문서이고, 서명 없는 판은 그동안에도 발행 관문에서 거절된다
|
|
41
|
+
* (아키텍트 조건 ①). 여기서 spec 을 쓰면 「올렸다」가 곧 「껐다」가 된다 — 이 파일에는 spec 을
|
|
42
|
+
* 쓰는 줄이 없어야 한다(`station-screen-control-withdrawal.test.ts` 가 센다).
|
|
43
|
+
*
|
|
44
|
+
* ── 무엇을 거둘지는 올릴 때 굳힌다 ─────────────────────────────────────────
|
|
45
|
+
* spec 의 **id** 와 방식(끄기 · 지우기)을 싣는다. 승인 콜백은 그것만 한다(조건 ②).
|
|
46
|
+
*
|
|
47
|
+
* ── 결재선은 발행 승인의 것을 **올리는 순간** 읽어 싣는다 ─────────────────
|
|
48
|
+
* 이 문 자신의 결재선 칸은 쓰지 않는다. 같은 결재선을 값으로 두 번 두면 갈린다.
|
|
49
|
+
*
|
|
50
|
+
* ── 이 문을 여는 자리 ─────────────────────────────────────────────────────
|
|
51
|
+
* 화면을 만드는 권한(`station:mutation`)을 든 자리가 올리고, 발행 승인의 결재선(품질)이 정한다 —
|
|
52
|
+
* 작성자는 승인하지 않는다(ADR-0047 ⑦).
|
|
53
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
54
|
+
*/
|
|
55
|
+
let StationScreenControlWithdrawalResolver = class StationScreenControlWithdrawalResolver {
|
|
56
|
+
async requestStationScreenControlWithdrawal(boardId, reason, remove, context) {
|
|
57
|
+
const { domain, tx } = context.state;
|
|
58
|
+
const scope = { domain: { id: domain.id } };
|
|
59
|
+
const spec = await tx.getRepository(station_screen_spec_1.StationScreenSpec).findOne({ where: { ...scope, boardId } });
|
|
60
|
+
const name = (0, station_screen_control_withdrawal_1.controlWithdrawalRequestName)(boardId);
|
|
61
|
+
const waiting = await tx.getRepository(worklist_1.ActivityInstance).findOne({
|
|
62
|
+
where: {
|
|
63
|
+
...scope,
|
|
64
|
+
name,
|
|
65
|
+
activity: { name: activity_station_screen_control_withdrawal_1.STATION_SCREEN_CONTROL_WITHDRAWAL_ACTIVITY },
|
|
66
|
+
state: (0, typeorm_1.In)(OPEN_STATES)
|
|
67
|
+
},
|
|
68
|
+
relations: ['activity']
|
|
69
|
+
});
|
|
70
|
+
const activity = await (0, worklist_2.activityNamed)(activity_station_screen_control_withdrawal_1.STATION_SCREEN_CONTROL_WITHDRAWAL_ACTIVITY, context);
|
|
71
|
+
const control = await controlLineStanding(context);
|
|
72
|
+
/* 읽기만 여기서 하고 **판단은 한 곳에서** 한다 — 조건이 여기 있으면 거동 시험이 못 본다(§`assertWithdrawalRaisable`). */
|
|
73
|
+
(0, station_screen_control_withdrawal_1.assertWithdrawalRaisable)({ reason, spec, waiting: !!waiting, installed: !!activity, line: control.standing });
|
|
74
|
+
/* 이름은 **서버가 읽는다.** 무엇을 승인했는지 묻는 자리라 올린 쪽이 보낸 이름을 믿지 않는다. */
|
|
75
|
+
const board = await (0, shell_1.getRepository)(board_service_1.Board).findOne({ where: { id: boardId } });
|
|
76
|
+
const screenName = board?.name ?? boardId;
|
|
77
|
+
const action = remove ? 'delete' : 'turn-off';
|
|
78
|
+
const instance = await (0, worklist_1.issue)({
|
|
79
|
+
name,
|
|
80
|
+
description: `${screenName} — ${reason.trim()}`,
|
|
81
|
+
activityId: activity.id,
|
|
82
|
+
/* 이 문의 결재선이 아니라 **발행 승인의 결재선**이다(머리말). */
|
|
83
|
+
approvalLine: control.activity?.approvalLine,
|
|
84
|
+
requireApproval: true,
|
|
85
|
+
threadsMin: 1,
|
|
86
|
+
input: {
|
|
87
|
+
boardId,
|
|
88
|
+
headline: action === 'delete'
|
|
89
|
+
? `${screenName} 의 화면 설정을 지우고 통제에서 뺍니다`
|
|
90
|
+
: `${screenName} 를 통제 문서에서 뺍니다`,
|
|
91
|
+
consequences: {
|
|
92
|
+
after: '승인하면 이 화면은 그 뒤로 결재 없이 발행됩니다. 작업자가 보는 판이 서명 없이 바뀔 수 있습니다.'
|
|
93
|
+
},
|
|
94
|
+
/* 방식마다 무게가 다르다 — 끄는 것은 다시 켤 수 있고, 지우는 것은 못 되돌린다. 사유(caveat)와 함께 싣는다. */
|
|
95
|
+
reversibility: (0, station_screen_control_withdrawal_1.withdrawalReversibility)(action),
|
|
96
|
+
/* The settings as they were, so a deletion can be set up again from this record (ADR-0064 ③). */
|
|
97
|
+
before: (0, station_screen_control_withdrawal_1.stationScreenSpecBefore)(spec),
|
|
98
|
+
withdrawal: {
|
|
99
|
+
name,
|
|
100
|
+
/* 승인 때 **이 id** 만 다룬다 — 그 사이 지우고 새로 만든 설정은 결재자가 본 것이 아니다. */
|
|
101
|
+
specId: spec.id,
|
|
102
|
+
boardId,
|
|
103
|
+
screenName,
|
|
104
|
+
action,
|
|
105
|
+
reason: reason.trim(),
|
|
106
|
+
requestedAt: new Date().toISOString()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}, context);
|
|
110
|
+
return instance.id;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
exports.StationScreenControlWithdrawalResolver = StationScreenControlWithdrawalResolver;
|
|
114
|
+
tslib_1.__decorate([
|
|
115
|
+
(0, type_graphql_1.Directive)('@privilege(category: "station", privilege: "mutation", domainOwnerGranted: true)'),
|
|
116
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
117
|
+
(0, type_graphql_1.Mutation)(returns => String, { description: 'Ask for approval to take one station screen out of document control' }),
|
|
118
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('boardId')),
|
|
119
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('reason')),
|
|
120
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('remove', { nullable: true, description: 'delete the station spec instead of only turning control off' })),
|
|
121
|
+
tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
|
|
122
|
+
tslib_1.__metadata("design:type", Function),
|
|
123
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Boolean, Object]),
|
|
124
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
125
|
+
], StationScreenControlWithdrawalResolver.prototype, "requestStationScreenControlWithdrawal", null);
|
|
126
|
+
exports.StationScreenControlWithdrawalResolver = StationScreenControlWithdrawalResolver = tslib_1.__decorate([
|
|
127
|
+
(0, type_graphql_1.Resolver)(),
|
|
128
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
|
|
129
|
+
], StationScreenControlWithdrawalResolver);
|
|
130
|
+
//# sourceMappingURL=station-screen-control-withdrawal-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"station-screen-control-withdrawal-resolver.js","sourceRoot":"","sources":["../../../server/service/station/station-screen-control-withdrawal-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { getRepository, SpeakRefusals } from '@things-factory/shell'\nimport { Board } from '@things-factory/board-service'\nimport { ActivityInstance, ActivityInstanceStatus, issue } from '@things-factory/worklist'\n\nimport { STATION_SCREEN_CONTROL_WITHDRAWAL_ACTIVITY } from '../../activities/activity-station-screen-control-withdrawal'\nimport { STATION_SCREEN_RELEASE_ACTIVITY } from '../../activities/activity-station-screen-release'\nimport { activityNamed, approvalLineStanding } from '@things-factory/worklist'\nimport type { ApprovalLineStanding } from '@things-factory/worklist'\nimport { assertWithdrawalRaisable, controlWithdrawalRequestName, withdrawalReversibility, stationScreenSpecBefore } from './station-screen-control-withdrawal'\nimport type { ControlWithdrawalAction } from './station-screen-control-withdrawal'\nimport { StationScreenSpec } from './station-screen-spec'\n\n/** 아직 끝나지 않은 상태들 — 끝난 것과 접힌 것만 뺀다(§`disposition-pending`). */\nconst OPEN_STATES = [\n ActivityInstanceStatus.Draft,\n ActivityInstanceStatus.Issued,\n ActivityInstanceStatus.Unassigned,\n ActivityInstanceStatus.Assigned,\n ActivityInstanceStatus.Started,\n ActivityInstanceStatus.Pending\n]\n\n/**\n * **통제를 켜고 끄는 결재선** — 화면 발행 승인의 결재선 하나다.\n *\n * 켤 때(`saveStationScreenSpec`)와 끌 때(`requestStationScreenControlWithdrawal`)가 **같은 함수로**\n * 판정한다. 둘이 따로 읽으면, 켤 수는 없는데 끌 수는 있는(또는 그 반대의) 공장이 생긴다.\n */\nexport async function controlLineStanding(\n context: ResolverContext\n): Promise<{ activity?: { id?: string; approvalLine?: unknown[] }; standing: ApprovalLineStanding }> {\n const activity = await activityNamed(STATION_SCREEN_RELEASE_ACTIVITY, context)\n\n return { activity, standing: await approvalLineStanding(activity, context) }\n}\n\n/**\n * 통제 문서를 **통제 밖으로 내보내자고 결재에 올린다.**\n *\n * ═══════════════════════════════════════════════════════════════════════════\n * ── 올리기만 한다. spec 은 그대로다 ────────────────────────────────────────\n * 승인 전까지 이 화면은 여전히 통제 문서이고, 서명 없는 판은 그동안에도 발행 관문에서 거절된다\n * (아키텍트 조건 ①). 여기서 spec 을 쓰면 「올렸다」가 곧 「껐다」가 된다 — 이 파일에는 spec 을\n * 쓰는 줄이 없어야 한다(`station-screen-control-withdrawal.test.ts` 가 센다).\n *\n * ── 무엇을 거둘지는 올릴 때 굳힌다 ─────────────────────────────────────────\n * spec 의 **id** 와 방식(끄기 · 지우기)을 싣는다. 승인 콜백은 그것만 한다(조건 ②).\n *\n * ── 결재선은 발행 승인의 것을 **올리는 순간** 읽어 싣는다 ─────────────────\n * 이 문 자신의 결재선 칸은 쓰지 않는다. 같은 결재선을 값으로 두 번 두면 갈린다.\n *\n * ── 이 문을 여는 자리 ─────────────────────────────────────────────────────\n * 화면을 만드는 권한(`station:mutation`)을 든 자리가 올리고, 발행 승인의 결재선(품질)이 정한다 —\n * 작성자는 승인하지 않는다(ADR-0047 ⑦).\n * ═══════════════════════════════════════════════════════════════════════════\n */\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class StationScreenControlWithdrawalResolver {\n @Directive('@privilege(category: \"station\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => String, { description: 'Ask for approval to take one station screen out of document control' })\n async requestStationScreenControlWithdrawal(\n @Arg('boardId') boardId: string,\n @Arg('reason') reason: string,\n @Arg('remove', { nullable: true, description: 'delete the station spec instead of only turning control off' })\n remove: boolean | undefined,\n @Ctx() context: ResolverContext\n ): Promise<string> {\n const { domain, tx } = context.state\n const scope = { domain: { id: domain.id } }\n\n const spec = await tx.getRepository(StationScreenSpec).findOne({ where: { ...scope, boardId } })\n const name = controlWithdrawalRequestName(boardId)\n\n const waiting = await tx.getRepository(ActivityInstance).findOne({\n where: {\n ...scope,\n name,\n activity: { name: STATION_SCREEN_CONTROL_WITHDRAWAL_ACTIVITY },\n state: In(OPEN_STATES)\n },\n relations: ['activity']\n })\n\n const activity = await activityNamed(STATION_SCREEN_CONTROL_WITHDRAWAL_ACTIVITY, context)\n const control = await controlLineStanding(context)\n\n /* 읽기만 여기서 하고 **판단은 한 곳에서** 한다 — 조건이 여기 있으면 거동 시험이 못 본다(§`assertWithdrawalRaisable`). */\n assertWithdrawalRaisable({ reason, spec, waiting: !!waiting, installed: !!activity, line: control.standing })\n\n /* 이름은 **서버가 읽는다.** 무엇을 승인했는지 묻는 자리라 올린 쪽이 보낸 이름을 믿지 않는다. */\n const board = await getRepository(Board).findOne({ where: { id: boardId } })\n const screenName = board?.name ?? boardId\n const action: ControlWithdrawalAction = remove ? 'delete' : 'turn-off'\n\n const instance = await issue(\n {\n name,\n description: `${screenName} — ${reason.trim()}`,\n activityId: activity!.id,\n /* 이 문의 결재선이 아니라 **발행 승인의 결재선**이다(머리말). */\n approvalLine: control.activity?.approvalLine,\n requireApproval: true,\n threadsMin: 1,\n input: {\n boardId,\n headline:\n action === 'delete'\n ? `${screenName} 의 화면 설정을 지우고 통제에서 뺍니다`\n : `${screenName} 를 통제 문서에서 뺍니다`,\n consequences: {\n after: '승인하면 이 화면은 그 뒤로 결재 없이 발행됩니다. 작업자가 보는 판이 서명 없이 바뀔 수 있습니다.'\n },\n /* 방식마다 무게가 다르다 — 끄는 것은 다시 켤 수 있고, 지우는 것은 못 되돌린다. 사유(caveat)와 함께 싣는다. */\n reversibility: withdrawalReversibility(action) as { reversible: boolean; caveat: string },\n /* The settings as they were, so a deletion can be set up again from this record (ADR-0064 ③). */\n before: stationScreenSpecBefore(spec!),\n withdrawal: {\n name,\n /* 승인 때 **이 id** 만 다룬다 — 그 사이 지우고 새로 만든 설정은 결재자가 본 것이 아니다. */\n specId: spec!.id,\n boardId,\n screenName,\n action,\n reason: reason.trim(),\n requestedAt: new Date().toISOString()\n }\n }\n } as any,\n context\n )\n\n return instance.id\n }\n}\n"]}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **통제 문서의 통제를 거두는 일** — 켜는 것만 막고 끄는 것을 열어 두면 통제가 한 방향으로만 선다.
|
|
3
|
+
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* ── 무엇이 열려 있었나 ─────────────────────────────────────────────────────
|
|
6
|
+
* 통제를 **켤 때**는 결재선이 있어야 했다(`turnsControlOn`). 그런데 `controlled: false` 로 저장하거나
|
|
7
|
+
* spec 을 지우는 데는 관문이 없었고, 발행 관문은 통제가 아닌 화면을 그대로 통과시킨다
|
|
8
|
+
* (`station-screen-publish-subscriber.ts` — `if (!spec?.controlled) return`). 그래서 화면을 만드는
|
|
9
|
+
* 권한만 든 작성자가 통제를 끄고 **서명 없는 도안을 발행**할 수 있었다.
|
|
10
|
+
*
|
|
11
|
+
* 판정(ADR-0047 ⑨): **결재로 세운 것은 결재로 거둔다.** 통제를 끄는 것과 통제 중인 spec 을 지우는
|
|
12
|
+
* 것은 발행 승인과 **같은 결재선**을 지난다. 끄는 것이 결재를 지났다면 발행 관문의 그 return 은
|
|
13
|
+
* 정당하다 — 그래서 관문은 그대로 둔다.
|
|
14
|
+
*
|
|
15
|
+
* ── 여기 있는 것 ──────────────────────────────────────────────────────────
|
|
16
|
+
* 판단만 둔다. DB 를 읽는 것은 부르는 쪽의 일이다 — 이 판단이 틀리면 통제 문서가 뚫리는데, 그것을
|
|
17
|
+
* 확인하는 시험이 DB·보드·spec·결재를 다 세운 뒤에야 물을 수 있으면 안 묻게 된다.
|
|
18
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
19
|
+
*/
|
|
20
|
+
import { type ApprovalLineStanding } from '@things-factory/worklist';
|
|
21
|
+
import { type Reversibility } from '@things-factory/shell';
|
|
22
|
+
/** 거두는 방식 둘 — 상신 때 정하고, 승인 때 그대로 한다. */
|
|
23
|
+
export declare const CONTROL_WITHDRAWAL_ACTIONS: readonly ["turn-off", "delete"];
|
|
24
|
+
export type ControlWithdrawalAction = (typeof CONTROL_WITHDRAWAL_ACTIONS)[number];
|
|
25
|
+
/**
|
|
26
|
+
* Both are reversible (ADR-0064, conditions for `reversible`): turning control on again and saving the
|
|
27
|
+
* settings again are the paired operations, releases are kept by board and not by the settings row's id,
|
|
28
|
+
* and the delete raise carries the settings as they were (`stationScreenSpecBefore`), so the approval
|
|
29
|
+
* record holds what to set up again.
|
|
30
|
+
*/
|
|
31
|
+
export declare const WITHDRAWAL_REVERSIBILITY: Record<ControlWithdrawalAction, Reversibility>;
|
|
32
|
+
/**
|
|
33
|
+
* 승인 콜백이 **하지 않고 끝내는** 사유.
|
|
34
|
+
*
|
|
35
|
+
* 상신과 승인 사이에 그 spec 이 바뀔 수 있다. 콜백은 상신 때 굳힌 것만 하고, 그 사이 들어온 변경을
|
|
36
|
+
* 덮지 않는다 — 그러면 조용히 성공하는 대신 이 코드로 멈춘다.
|
|
37
|
+
*/
|
|
38
|
+
export type ControlWithdrawalRefusal =
|
|
39
|
+
/** 상신 때 가리킨 spec 이 이제 없다. */
|
|
40
|
+
'control-withdrawal-spec-gone'
|
|
41
|
+
/** 그 spec 은 이미 통제가 아니다 — 거둘 것이 없다. */
|
|
42
|
+
| 'control-already-off';
|
|
43
|
+
/**
|
|
44
|
+
* 이 저장이 통제를 **끄는** 저장인가.
|
|
45
|
+
*
|
|
46
|
+
* `after` 가 비어 있으면 끄는 것이 아니다 — 흐름만 저장하는 요청은 `controlled` 를 안 싣는다
|
|
47
|
+
* (§`saveStationScreenSpec`). 그것을 끄는 것으로 읽으면 통제 문서를 고칠 수조차 없게 된다.
|
|
48
|
+
*/
|
|
49
|
+
export declare function turnsControlOff(before: boolean | null | undefined, after: boolean | null | undefined): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* 승인된 지금 **상신 때 굳힌 것을 그대로 할 수 있는가** — 할 수 없으면 그 사유.
|
|
52
|
+
*
|
|
53
|
+
* `standing` 은 콜백이 **상신 때 굳힌 id 로** 다시 읽은 spec 이다. boardId 로 다시 찾지 않는다 — 그
|
|
54
|
+
* 사이 지우고 새로 만든 spec 은 결재자가 본 것이 아니다.
|
|
55
|
+
*/
|
|
56
|
+
export declare function whyNotWithdraw(standing: {
|
|
57
|
+
controlled?: boolean | null;
|
|
58
|
+
} | null | undefined): ControlWithdrawalRefusal | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* 되돌릴 수 있는가 — **방식마다 다르다.**
|
|
61
|
+
*
|
|
62
|
+
* 끄는 것은 다시 켤 수 있다. 다만 꺼져 있던 동안 서명 없이 나간 판은 되돌아오지 않는다. 지우는 것은
|
|
63
|
+
* 흐름·요구 축·통제 표시가 함께 사라져 되돌릴 길이 없다 — 다시 만드는 것은 새로 짓는 일이다.
|
|
64
|
+
*/
|
|
65
|
+
export declare function withdrawalReversibility(action: ControlWithdrawalAction): {
|
|
66
|
+
reversible: boolean;
|
|
67
|
+
caveat: string;
|
|
68
|
+
};
|
|
69
|
+
/** 상신 이름 — 읽는 쪽과 올리는 쪽이 같은 이름을 써야 겹친 상신을 찾는다. */
|
|
70
|
+
export declare function controlWithdrawalRequestName(boardId: string): string;
|
|
71
|
+
/** 올릴 때 본 것 — 읽는 것은 리졸버가 하고, 이 판단은 DB 를 모른다. */
|
|
72
|
+
export interface WithdrawalRaiseReading {
|
|
73
|
+
reason?: string | null;
|
|
74
|
+
spec?: {
|
|
75
|
+
controlled?: boolean | null;
|
|
76
|
+
} | null;
|
|
77
|
+
/** 같은 화면의 해제가 이미 결재 중인가. */
|
|
78
|
+
waiting: boolean;
|
|
79
|
+
/** 통제 해제 승인 양식이 이 공장에 섰나. */
|
|
80
|
+
installed: boolean;
|
|
81
|
+
/** **화면 발행 승인**의 결재선 판정 — 켤 때와 같은 함수가 낸 것(`controlLineStanding`). */
|
|
82
|
+
line: ApprovalLineStanding;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 올려도 되는가 — **안 되면 던진다.** 리졸버에는 조건이 없고 이 함수를 부르기만 한다.
|
|
86
|
+
*
|
|
87
|
+
* ── 왜 판단이 던지나 ───────────────────────────────────────────────────────
|
|
88
|
+
* 리졸버에 `if (refusal) throw` 를 두면, 그 조건이 죽어도(`if (false && …)`) 글자는 남는다. 글자로
|
|
89
|
+
* 문을 세는 분류기(`irreversible-doors-refuse.test.ts`)는 그것을 「거절한다」로 읽는다 — 거절하는 글자가
|
|
90
|
+
* 있는지를 셀 뿐 거절이 **도는지**는 못 본다. 그 층은 거동 시험이 맡는다
|
|
91
|
+
* (`station-screen-control-withdrawal.test.ts`, 아키텍트 2026-09-17). 조건을 이 함수 하나에 모아야 거동
|
|
92
|
+
* 시험이 부르는 것이 곧 상신이 부르는 것이 된다.
|
|
93
|
+
*/
|
|
94
|
+
export declare function assertWithdrawalRaisable(reading: WithdrawalRaiseReading): void;
|
|
95
|
+
/** The settings' content columns — what a person needs to set the same screen up again. */
|
|
96
|
+
export declare const STATION_SCREEN_SPEC_CONTENT: readonly ["boardId", "requires", "target", "controlled", "kind", "flow"];
|
|
97
|
+
/**
|
|
98
|
+
* The settings as they were before deletion, carried in the approval record. It is what makes the delete
|
|
99
|
+
* branch reversible: the flow, read axes and control mark stay readable after the row is gone
|
|
100
|
+
* (ADR-0064, condition ③ for `reversible`).
|
|
101
|
+
*/
|
|
102
|
+
export declare function stationScreenSpecBefore(spec: Partial<Record<(typeof STATION_SCREEN_SPEC_CONTENT)[number], unknown>>): {
|
|
103
|
+
[k: string]: unknown;
|
|
104
|
+
};
|