@things-factory/ops-master 10.0.18 → 10.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/pages/master-axes.js +20 -7
- package/dist-client/pages/master-axes.js.map +1 -1
- package/dist-client/pages/master-list.d.ts +3 -3
- package/dist-client/pages/master-list.js +10 -38
- package/dist-client/pages/master-list.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/index.d.ts +9 -2
- package/dist-server/service/index.js +11 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/master-axis.d.ts +1 -1
- package/dist-server/service/master-axis.js +16 -1
- package/dist-server/service/master-axis.js.map +1 -1
- package/dist-server/service/operation/index.d.ts +2 -1
- package/dist-server/service/operation/index.js +2 -1
- package/dist-server/service/operation/index.js.map +1 -1
- package/dist-server/service/operation/operation-readiness-resolver.d.ts +39 -0
- package/dist-server/service/operation/operation-readiness-resolver.js +111 -0
- package/dist-server/service/operation/operation-readiness-resolver.js.map +1 -0
- package/dist-server/service/operation/operation-readiness.d.ts +34 -0
- package/dist-server/service/operation/operation-readiness.js +133 -0
- package/dist-server/service/operation/operation-readiness.js.map +1 -0
- package/dist-server/service/personnel/personnel-class-readiness.d.ts +22 -0
- package/dist-server/service/personnel/personnel-class-readiness.js +98 -0
- package/dist-server/service/personnel/personnel-class-readiness.js.map +1 -0
- package/dist-server/service/personnel/qualification.d.ts +7 -0
- package/dist-server/service/personnel/qualification.js +25 -0
- package/dist-server/service/personnel/qualification.js.map +1 -1
- package/dist-server/service/recipe/index.d.ts +9 -0
- package/dist-server/service/recipe/index.js +14 -0
- package/dist-server/service/recipe/index.js.map +1 -0
- package/dist-server/service/recipe/recipe-definition.d.ts +71 -0
- package/dist-server/service/recipe/recipe-definition.js +130 -0
- package/dist-server/service/recipe/recipe-definition.js.map +1 -0
- package/dist-server/service/recipe/recipe-master-resolver.d.ts +28 -0
- package/dist-server/service/recipe/recipe-master-resolver.js +124 -0
- package/dist-server/service/recipe/recipe-master-resolver.js.map +1 -0
- package/dist-server/service/recipe/recipe-master.d.ts +37 -0
- package/dist-server/service/recipe/recipe-master.js +47 -0
- package/dist-server/service/recipe/recipe-master.js.map +1 -0
- package/dist-server/service/recipe/recipe-query.d.ts +13 -0
- package/dist-server/service/recipe/recipe-query.js +54 -0
- package/dist-server/service/recipe/recipe-query.js.map +1 -0
- package/dist-server/service/recipe/route-definition.d.ts +51 -0
- package/dist-server/service/recipe/route-definition.js +113 -0
- package/dist-server/service/recipe/route-definition.js.map +1 -0
- package/dist-server/service/status/master-status.d.ts +0 -7
- package/dist-server/service/status/master-status.js +5 -6
- package/dist-server/service/status/master-status.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/translations/en.json +3 -3
- package/translations/ja.json +5 -1
- package/translations/ko.json +3 -3
- package/translations/ms.json +5 -1
- package/translations/zh.json +5 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RouteDefinitionResolver = exports.RecipeDefinitionResolver = exports.RouteDefinitionList = exports.RecipeDefinitionList = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
|
+
const master_crud_1 = require("../master-crud");
|
|
8
|
+
const master_axis_1 = require("../master-axis");
|
|
9
|
+
const master_list_1 = require("../master-list");
|
|
10
|
+
const recipe_definition_1 = require("./recipe-definition");
|
|
11
|
+
const route_definition_1 = require("./route-definition");
|
|
12
|
+
/**
|
|
13
|
+
* 레시피·라우트 축을 채우고 고친다.
|
|
14
|
+
*
|
|
15
|
+
* 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다 — 다른 열셋과 같은 모양이다.
|
|
16
|
+
*
|
|
17
|
+
* **개정할 때 행을 고치지 않고 유효 기간의 끝을 채운다.** 고치면 그 레시피로 만든 지난 실적이 어느
|
|
18
|
+
* 배합으로 만든 것인지 잃는다.
|
|
19
|
+
*/
|
|
20
|
+
let RecipeDefinitionList = class RecipeDefinitionList {
|
|
21
|
+
};
|
|
22
|
+
exports.RecipeDefinitionList = RecipeDefinitionList;
|
|
23
|
+
tslib_1.__decorate([
|
|
24
|
+
(0, type_graphql_1.Field)(type => [recipe_definition_1.RecipeDefinition]),
|
|
25
|
+
tslib_1.__metadata("design:type", Array)
|
|
26
|
+
], RecipeDefinitionList.prototype, "items", void 0);
|
|
27
|
+
tslib_1.__decorate([
|
|
28
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int),
|
|
29
|
+
tslib_1.__metadata("design:type", Number)
|
|
30
|
+
], RecipeDefinitionList.prototype, "total", void 0);
|
|
31
|
+
exports.RecipeDefinitionList = RecipeDefinitionList = tslib_1.__decorate([
|
|
32
|
+
(0, type_graphql_1.ObjectType)({ description: 'A page of recipe definitions' })
|
|
33
|
+
], RecipeDefinitionList);
|
|
34
|
+
let RouteDefinitionList = class RouteDefinitionList {
|
|
35
|
+
};
|
|
36
|
+
exports.RouteDefinitionList = RouteDefinitionList;
|
|
37
|
+
tslib_1.__decorate([
|
|
38
|
+
(0, type_graphql_1.Field)(type => [route_definition_1.RouteDefinition]),
|
|
39
|
+
tslib_1.__metadata("design:type", Array)
|
|
40
|
+
], RouteDefinitionList.prototype, "items", void 0);
|
|
41
|
+
tslib_1.__decorate([
|
|
42
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int),
|
|
43
|
+
tslib_1.__metadata("design:type", Number)
|
|
44
|
+
], RouteDefinitionList.prototype, "total", void 0);
|
|
45
|
+
exports.RouteDefinitionList = RouteDefinitionList = tslib_1.__decorate([
|
|
46
|
+
(0, type_graphql_1.ObjectType)({ description: 'A page of route definitions' })
|
|
47
|
+
], RouteDefinitionList);
|
|
48
|
+
let RecipeDefinitionResolver = class RecipeDefinitionResolver {
|
|
49
|
+
async recipeDefinitions(params, context) {
|
|
50
|
+
const { domain } = context.state;
|
|
51
|
+
const { items, total } = await (0, master_list_1.listMaster)('recipeDefinition', params, domain);
|
|
52
|
+
return { items: items, total };
|
|
53
|
+
}
|
|
54
|
+
async updateMultipleRecipeDefinition(patches, context) {
|
|
55
|
+
const { domain, user, tx } = context.state;
|
|
56
|
+
const axis = (0, master_axis_1.masterAxisOf)('recipeDefinition');
|
|
57
|
+
const saved = await (0, master_crud_1.saveMasterPatches)(tx, domain, axis.entity, patches, user, {
|
|
58
|
+
hasEffectivePeriod: axis.hasEffectivePeriod
|
|
59
|
+
});
|
|
60
|
+
return saved;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
exports.RecipeDefinitionResolver = RecipeDefinitionResolver;
|
|
64
|
+
tslib_1.__decorate([
|
|
65
|
+
(0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "query", domainOwnerGranted: true)'),
|
|
66
|
+
(0, type_graphql_1.Query)(returns => RecipeDefinitionList, { description: 'To fetch recipe definitions' }),
|
|
67
|
+
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
68
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
69
|
+
tslib_1.__metadata("design:type", Function),
|
|
70
|
+
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
71
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
72
|
+
], RecipeDefinitionResolver.prototype, "recipeDefinitions", null);
|
|
73
|
+
tslib_1.__decorate([
|
|
74
|
+
(0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "mutation", domainOwnerGranted: true)'),
|
|
75
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
76
|
+
(0, type_graphql_1.Mutation)(returns => [recipe_definition_1.RecipeDefinition], { description: 'To create, change or retire recipe definitions' }),
|
|
77
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [shell_1.ScalarObject])),
|
|
78
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
79
|
+
tslib_1.__metadata("design:type", Function),
|
|
80
|
+
tslib_1.__metadata("design:paramtypes", [Array, Object]),
|
|
81
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
82
|
+
], RecipeDefinitionResolver.prototype, "updateMultipleRecipeDefinition", null);
|
|
83
|
+
exports.RecipeDefinitionResolver = RecipeDefinitionResolver = tslib_1.__decorate([
|
|
84
|
+
(0, type_graphql_1.Resolver)(recipe_definition_1.RecipeDefinition)
|
|
85
|
+
], RecipeDefinitionResolver);
|
|
86
|
+
let RouteDefinitionResolver = class RouteDefinitionResolver {
|
|
87
|
+
async routeDefinitions(params, context) {
|
|
88
|
+
const { domain } = context.state;
|
|
89
|
+
const { items, total } = await (0, master_list_1.listMaster)('routeDefinition', params, domain);
|
|
90
|
+
return { items: items, total };
|
|
91
|
+
}
|
|
92
|
+
async updateMultipleRouteDefinition(patches, context) {
|
|
93
|
+
const { domain, user, tx } = context.state;
|
|
94
|
+
const axis = (0, master_axis_1.masterAxisOf)('routeDefinition');
|
|
95
|
+
const saved = await (0, master_crud_1.saveMasterPatches)(tx, domain, axis.entity, patches, user, {
|
|
96
|
+
hasEffectivePeriod: axis.hasEffectivePeriod
|
|
97
|
+
});
|
|
98
|
+
return saved;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
exports.RouteDefinitionResolver = RouteDefinitionResolver;
|
|
102
|
+
tslib_1.__decorate([
|
|
103
|
+
(0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "query", domainOwnerGranted: true)'),
|
|
104
|
+
(0, type_graphql_1.Query)(returns => RouteDefinitionList, { description: 'To fetch route definitions' }),
|
|
105
|
+
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
106
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
107
|
+
tslib_1.__metadata("design:type", Function),
|
|
108
|
+
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
109
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
110
|
+
], RouteDefinitionResolver.prototype, "routeDefinitions", null);
|
|
111
|
+
tslib_1.__decorate([
|
|
112
|
+
(0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "mutation", domainOwnerGranted: true)'),
|
|
113
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
114
|
+
(0, type_graphql_1.Mutation)(returns => [route_definition_1.RouteDefinition], { description: 'To create, change or retire route definitions' }),
|
|
115
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [shell_1.ScalarObject])),
|
|
116
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
117
|
+
tslib_1.__metadata("design:type", Function),
|
|
118
|
+
tslib_1.__metadata("design:paramtypes", [Array, Object]),
|
|
119
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
120
|
+
], RouteDefinitionResolver.prototype, "updateMultipleRouteDefinition", null);
|
|
121
|
+
exports.RouteDefinitionResolver = RouteDefinitionResolver = tslib_1.__decorate([
|
|
122
|
+
(0, type_graphql_1.Resolver)(route_definition_1.RouteDefinition)
|
|
123
|
+
], RouteDefinitionResolver);
|
|
124
|
+
//# sourceMappingURL=recipe-master-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-master-resolver.js","sourceRoot":"","sources":["../../../server/service/recipe/recipe-master-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Args, Arg, Ctx, Directive, Int, Mutation, ObjectType, Field, Query, Resolver } from 'type-graphql'\n\nimport { ListParam, ScalarObject } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { RecipeDefinition } from './recipe-definition'\nimport { RouteDefinition } from './route-definition'\n\n/**\n * 레시피·라우트 축을 채우고 고친다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다 — 다른 열셋과 같은 모양이다.\n *\n * **개정할 때 행을 고치지 않고 유효 기간의 끝을 채운다.** 고치면 그 레시피로 만든 지난 실적이 어느\n * 배합으로 만든 것인지 잃는다.\n */\n\n@ObjectType({ description: 'A page of recipe definitions' })\nexport class RecipeDefinitionList {\n @Field(type => [RecipeDefinition])\n items: RecipeDefinition[]\n\n @Field(type => Int)\n total: number\n}\n\n@ObjectType({ description: 'A page of route definitions' })\nexport class RouteDefinitionList {\n @Field(type => [RouteDefinition])\n items: RouteDefinition[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(RecipeDefinition)\nexport class RecipeDefinitionResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => RecipeDefinitionList, { description: 'To fetch recipe definitions' })\n async recipeDefinitions(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<RecipeDefinitionList> {\n const { domain } = context.state\n const { items, total } = await listMaster('recipeDefinition', params, domain)\n\n return { items: items as RecipeDefinition[], total }\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [RecipeDefinition], { description: 'To create, change or retire recipe definitions' })\n async updateMultipleRecipeDefinition(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<RecipeDefinition[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('recipeDefinition')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as RecipeDefinition[]\n }\n}\n\n@Resolver(RouteDefinition)\nexport class RouteDefinitionResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => RouteDefinitionList, { description: 'To fetch route definitions' })\n async routeDefinitions(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<RouteDefinitionList> {\n const { domain } = context.state\n const { items, total } = await listMaster('routeDefinition', params, domain)\n\n return { items: items as RouteDefinition[], total }\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [RouteDefinition], { description: 'To create, change or retire route definitions' })\n async updateMultipleRouteDefinition(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<RouteDefinition[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('routeDefinition')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as RouteDefinition[]\n }\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { RecipeDefinition } from './recipe-definition';
|
|
2
|
+
import type { RouteDefinition } from './route-definition';
|
|
3
|
+
/**
|
|
4
|
+
* 트윈 선언의 `recipes`·`routes` 한 항목 — 계약의 `RecipeDef`·`RouteDef` 모양이다.
|
|
5
|
+
*
|
|
6
|
+
* 마스터가 다른 모양으로 들면 옮기는 코드가 두 겹이 되고, 그 코드가 언젠가 어긋난다. 그래서 칸 이름을
|
|
7
|
+
* 계약과 같게 둔다 — 다른 것은 마스터가 `name` 으로 부르는 것을 계약이 `key` 로 부르는 것 하나다.
|
|
8
|
+
*/
|
|
9
|
+
export interface RouteEntry {
|
|
10
|
+
key: string;
|
|
11
|
+
label: string;
|
|
12
|
+
steps: string[];
|
|
13
|
+
procedure?: unknown[];
|
|
14
|
+
effectiveStart?: string;
|
|
15
|
+
effectiveEnd?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RecipeEntry {
|
|
18
|
+
key: string;
|
|
19
|
+
label: string;
|
|
20
|
+
inputs: unknown[];
|
|
21
|
+
outputs: unknown[];
|
|
22
|
+
route?: string;
|
|
23
|
+
effectiveStart?: string;
|
|
24
|
+
effectiveEnd?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function toRouteEntry(route: RouteDefinition): RouteEntry;
|
|
27
|
+
export declare function toRecipeEntry(recipe: RecipeDefinition): RecipeEntry;
|
|
28
|
+
/**
|
|
29
|
+
* **이 품목을 만드는 레시피들** — 여럿일 수 있다.
|
|
30
|
+
*
|
|
31
|
+
* 하나를 골라 주지 않는다. 대체 레시피가 정상이고(첫 실 연동에서 경로가 둘 이상인 레시피가 306/471),
|
|
32
|
+
* 어느 것으로 만들지는 오더가 정하거나 사람이 고른다. 여기서 하나를 골라 주면 그 판정이 숨는다.
|
|
33
|
+
*
|
|
34
|
+
* 유효 기간은 여기서 걸러 내지 않는다 — 「지금 무엇을 쓸 수 있나」와 「그때 무엇을 썼나」가 다른 물음이고,
|
|
35
|
+
* 시각을 아는 것은 부르는 쪽이다.
|
|
36
|
+
*/
|
|
37
|
+
export declare function recipesFor(recipes: RecipeDefinition[], materialDefinitionName: string): RecipeEntry[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toRouteEntry = toRouteEntry;
|
|
4
|
+
exports.toRecipeEntry = toRecipeEntry;
|
|
5
|
+
exports.recipesFor = recipesFor;
|
|
6
|
+
const resource_class_1 = require("../resource/resource-class");
|
|
7
|
+
function toRouteEntry(route) {
|
|
8
|
+
/* `steps` 를 비울 수 없다 — 단계가 없는 라우트는 지나갈 곳이 없다. */
|
|
9
|
+
const out = {
|
|
10
|
+
key: route.name,
|
|
11
|
+
label: route.description ?? route.name,
|
|
12
|
+
steps: route.steps ?? []
|
|
13
|
+
};
|
|
14
|
+
(0, resource_class_1.put)(out, 'procedure', route.procedure);
|
|
15
|
+
(0, resource_class_1.put)(out, 'effectiveStart', (0, resource_class_1.iso)(route.effectiveStart));
|
|
16
|
+
(0, resource_class_1.put)(out, 'effectiveEnd', (0, resource_class_1.iso)(route.effectiveEnd));
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
function toRecipeEntry(recipe) {
|
|
20
|
+
/*
|
|
21
|
+
* `inputs` 와 `outputs` 를 비울 수 없다. 산출이 없으면 무엇을 만드는지 알 수 없고, 투입이 없으면
|
|
22
|
+
* 무엇으로 만드는지 알 수 없다 — 둘 중 하나만으로는 레시피가 아니다.
|
|
23
|
+
*/
|
|
24
|
+
const out = {
|
|
25
|
+
key: recipe.name,
|
|
26
|
+
label: recipe.description ?? recipe.name,
|
|
27
|
+
inputs: recipe.inputs ?? [],
|
|
28
|
+
outputs: recipe.outputs ?? []
|
|
29
|
+
};
|
|
30
|
+
(0, resource_class_1.put)(out, 'route', recipe.route);
|
|
31
|
+
(0, resource_class_1.put)(out, 'effectiveStart', (0, resource_class_1.iso)(recipe.effectiveStart));
|
|
32
|
+
(0, resource_class_1.put)(out, 'effectiveEnd', (0, resource_class_1.iso)(recipe.effectiveEnd));
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* **이 품목을 만드는 레시피들** — 여럿일 수 있다.
|
|
37
|
+
*
|
|
38
|
+
* 하나를 골라 주지 않는다. 대체 레시피가 정상이고(첫 실 연동에서 경로가 둘 이상인 레시피가 306/471),
|
|
39
|
+
* 어느 것으로 만들지는 오더가 정하거나 사람이 고른다. 여기서 하나를 골라 주면 그 판정이 숨는다.
|
|
40
|
+
*
|
|
41
|
+
* 유효 기간은 여기서 걸러 내지 않는다 — 「지금 무엇을 쓸 수 있나」와 「그때 무엇을 썼나」가 다른 물음이고,
|
|
42
|
+
* 시각을 아는 것은 부르는 쪽이다.
|
|
43
|
+
*/
|
|
44
|
+
function recipesFor(recipes, materialDefinitionName) {
|
|
45
|
+
return recipes.filter(r => r.materialDefinitionName === materialDefinitionName).map(toRecipeEntry);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=recipe-master.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-master.js","sourceRoot":"","sources":["../../../server/service/recipe/recipe-master.ts"],"names":[],"mappings":";;AA6BA,oCAWC;AAED,sCAeC;AAWD,gCAEC;AAtED,+DAAqD;AA6BrD,SAAgB,YAAY,CAAC,KAAsB;IACjD,gDAAgD;IAChD,MAAM,GAAG,GAA4B;QACnC,GAAG,EAAE,KAAK,CAAC,IAAI;QACf,KAAK,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI;QACtC,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;KACzB,CAAA;IACD,IAAA,oBAAG,EAAC,GAAG,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAA;IACtC,IAAA,oBAAG,EAAC,GAAG,EAAE,gBAAgB,EAAE,IAAA,oBAAG,EAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAA;IACrD,IAAA,oBAAG,EAAC,GAAG,EAAE,cAAc,EAAE,IAAA,oBAAG,EAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAA;IACjD,OAAO,GAA4B,CAAA;AACrC,CAAC;AAED,SAAgB,aAAa,CAAC,MAAwB;IACpD;;;OAGG;IACH,MAAM,GAAG,GAA4B;QACnC,GAAG,EAAE,MAAM,CAAC,IAAI;QAChB,KAAK,EAAE,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI;QACxC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;KAC9B,CAAA;IACD,IAAA,oBAAG,EAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IAC/B,IAAA,oBAAG,EAAC,GAAG,EAAE,gBAAgB,EAAE,IAAA,oBAAG,EAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAA;IACtD,IAAA,oBAAG,EAAC,GAAG,EAAE,cAAc,EAAE,IAAA,oBAAG,EAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;IAClD,OAAO,GAA6B,CAAA;AACtC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,UAAU,CAAC,OAA2B,EAAE,sBAA8B;IACpF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,KAAK,sBAAsB,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;AACpG,CAAC","sourcesContent":["import { iso, put } from '../resource/resource-class'\nimport type { RecipeDefinition } from './recipe-definition'\nimport type { RouteDefinition } from './route-definition'\n\n/**\n * 트윈 선언의 `recipes`·`routes` 한 항목 — 계약의 `RecipeDef`·`RouteDef` 모양이다.\n *\n * 마스터가 다른 모양으로 들면 옮기는 코드가 두 겹이 되고, 그 코드가 언젠가 어긋난다. 그래서 칸 이름을\n * 계약과 같게 둔다 — 다른 것은 마스터가 `name` 으로 부르는 것을 계약이 `key` 로 부르는 것 하나다.\n */\nexport interface RouteEntry {\n key: string\n label: string\n steps: string[]\n procedure?: unknown[]\n effectiveStart?: string\n effectiveEnd?: string\n}\n\nexport interface RecipeEntry {\n key: string\n label: string\n inputs: unknown[]\n outputs: unknown[]\n route?: string\n effectiveStart?: string\n effectiveEnd?: string\n}\n\nexport function toRouteEntry(route: RouteDefinition): RouteEntry {\n /* `steps` 를 비울 수 없다 — 단계가 없는 라우트는 지나갈 곳이 없다. */\n const out: Record<string, unknown> = {\n key: route.name,\n label: route.description ?? route.name,\n steps: route.steps ?? []\n }\n put(out, 'procedure', route.procedure)\n put(out, 'effectiveStart', iso(route.effectiveStart))\n put(out, 'effectiveEnd', iso(route.effectiveEnd))\n return out as unknown as RouteEntry\n}\n\nexport function toRecipeEntry(recipe: RecipeDefinition): RecipeEntry {\n /*\n * `inputs` 와 `outputs` 를 비울 수 없다. 산출이 없으면 무엇을 만드는지 알 수 없고, 투입이 없으면\n * 무엇으로 만드는지 알 수 없다 — 둘 중 하나만으로는 레시피가 아니다.\n */\n const out: Record<string, unknown> = {\n key: recipe.name,\n label: recipe.description ?? recipe.name,\n inputs: recipe.inputs ?? [],\n outputs: recipe.outputs ?? []\n }\n put(out, 'route', recipe.route)\n put(out, 'effectiveStart', iso(recipe.effectiveStart))\n put(out, 'effectiveEnd', iso(recipe.effectiveEnd))\n return out as unknown as RecipeEntry\n}\n\n/**\n * **이 품목을 만드는 레시피들** — 여럿일 수 있다.\n *\n * 하나를 골라 주지 않는다. 대체 레시피가 정상이고(첫 실 연동에서 경로가 둘 이상인 레시피가 306/471),\n * 어느 것으로 만들지는 오더가 정하거나 사람이 고른다. 여기서 하나를 골라 주면 그 판정이 숨는다.\n *\n * 유효 기간은 여기서 걸러 내지 않는다 — 「지금 무엇을 쓸 수 있나」와 「그때 무엇을 썼나」가 다른 물음이고,\n * 시각을 아는 것은 부르는 쪽이다.\n */\nexport function recipesFor(recipes: RecipeDefinition[], materialDefinitionName: string): RecipeEntry[] {\n return recipes.filter(r => r.materialDefinitionName === materialDefinitionName).map(toRecipeEntry)\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class RecipeMaster {
|
|
2
|
+
recipes: string;
|
|
3
|
+
routes: string;
|
|
4
|
+
}
|
|
5
|
+
export declare class RecipeQuery {
|
|
6
|
+
/**
|
|
7
|
+
* 레시피와 라우트를 **한 질의로** 낸다.
|
|
8
|
+
*
|
|
9
|
+
* 따로 물으면 그 사이에 마스터가 바뀌어 레시피가 없는 라우트를 가리키는 순간이 생긴다. 구조는
|
|
10
|
+
* 서로를 가리키므로 통째로 맞아야 한다 — 마스터를 당겨 가는 다른 축과 같은 규율이다.
|
|
11
|
+
*/
|
|
12
|
+
recipeMaster(context: ResolverContext): Promise<RecipeMaster>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecipeQuery = exports.RecipeMaster = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
|
+
const recipe_definition_1 = require("./recipe-definition");
|
|
8
|
+
const route_definition_1 = require("./route-definition");
|
|
9
|
+
const recipe_master_1 = require("./recipe-master");
|
|
10
|
+
let RecipeMaster = class RecipeMaster {
|
|
11
|
+
};
|
|
12
|
+
exports.RecipeMaster = RecipeMaster;
|
|
13
|
+
tslib_1.__decorate([
|
|
14
|
+
(0, type_graphql_1.Field)(type => String, { description: 'RecipeDef[] as JSON text' }),
|
|
15
|
+
tslib_1.__metadata("design:type", String)
|
|
16
|
+
], RecipeMaster.prototype, "recipes", void 0);
|
|
17
|
+
tslib_1.__decorate([
|
|
18
|
+
(0, type_graphql_1.Field)(type => String, { description: 'RouteDef[] as JSON text' }),
|
|
19
|
+
tslib_1.__metadata("design:type", String)
|
|
20
|
+
], RecipeMaster.prototype, "routes", void 0);
|
|
21
|
+
exports.RecipeMaster = RecipeMaster = tslib_1.__decorate([
|
|
22
|
+
(0, type_graphql_1.ObjectType)({ description: 'Recipes and routes as the twin receives them' })
|
|
23
|
+
], RecipeMaster);
|
|
24
|
+
let RecipeQuery = class RecipeQuery {
|
|
25
|
+
/**
|
|
26
|
+
* 레시피와 라우트를 **한 질의로** 낸다.
|
|
27
|
+
*
|
|
28
|
+
* 따로 물으면 그 사이에 마스터가 바뀌어 레시피가 없는 라우트를 가리키는 순간이 생긴다. 구조는
|
|
29
|
+
* 서로를 가리키므로 통째로 맞아야 한다 — 마스터를 당겨 가는 다른 축과 같은 규율이다.
|
|
30
|
+
*/
|
|
31
|
+
async recipeMaster(context) {
|
|
32
|
+
const { domain } = context.state;
|
|
33
|
+
const [recipes, routes] = await Promise.all([
|
|
34
|
+
(0, shell_1.getRepository)(recipe_definition_1.RecipeDefinition).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } }),
|
|
35
|
+
(0, shell_1.getRepository)(route_definition_1.RouteDefinition).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } })
|
|
36
|
+
]);
|
|
37
|
+
return {
|
|
38
|
+
recipes: JSON.stringify(recipes.map(recipe_master_1.toRecipeEntry)),
|
|
39
|
+
routes: JSON.stringify(routes.map(recipe_master_1.toRouteEntry))
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
exports.RecipeQuery = RecipeQuery;
|
|
44
|
+
tslib_1.__decorate([
|
|
45
|
+
(0, type_graphql_1.Query)(returns => RecipeMaster, { description: 'Recipes and routes for the twin to pull' }),
|
|
46
|
+
tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
|
|
47
|
+
tslib_1.__metadata("design:type", Function),
|
|
48
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
49
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
50
|
+
], RecipeQuery.prototype, "recipeMaster", null);
|
|
51
|
+
exports.RecipeQuery = RecipeQuery = tslib_1.__decorate([
|
|
52
|
+
(0, type_graphql_1.Resolver)(recipe_definition_1.RecipeDefinition)
|
|
53
|
+
], RecipeQuery);
|
|
54
|
+
//# sourceMappingURL=recipe-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-query.js","sourceRoot":"","sources":["../../../server/service/recipe/recipe-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAsE;AAEtE,iDAAqD;AAErD,2DAAsD;AACtD,yDAAoD;AACpD,mDAA6D;AAGtD,IAAM,YAAY,GAAlB,MAAM,YAAY;CAMxB,CAAA;AANY,oCAAY;AAEvB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,0BAA0B,EAAE,CAAC;;6CACpD;AAGf;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,yBAAyB,EAAE,CAAC;;4CACpD;uBALH,YAAY;IADxB,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,8CAA8C,EAAE,CAAC;GAC/D,YAAY,CAMxB;AAGM,IAAM,WAAW,GAAjB,MAAM,WAAW;IACtB;;;;;OAKG;IAEG,AAAN,KAAK,CAAC,YAAY,CAAQ,OAAwB;QAChD,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC1C,IAAA,qBAAa,EAAC,oCAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACtG,IAAA,qBAAa,EAAC,kCAAe,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;SACtG,CAAC,CAAA;QAEF,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,6BAAa,CAAC,CAAC;YACnD,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,4BAAY,CAAC,CAAC;SACjD,CAAA;IACH,CAAC;CACF,CAAA;AArBY,kCAAW;AAQhB;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,WAAW,EAAE,yCAAyC,EAAE,CAAC;IACvE,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;+CAYxB;sBApBU,WAAW;IADvB,IAAA,uBAAQ,EAAC,oCAAgB,CAAC;GACd,WAAW,CAqBvB","sourcesContent":["import { Ctx, Field, ObjectType, Query, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { RecipeDefinition } from './recipe-definition'\nimport { RouteDefinition } from './route-definition'\nimport { toRecipeEntry, toRouteEntry } from './recipe-master'\n\n@ObjectType({ description: 'Recipes and routes as the twin receives them' })\nexport class RecipeMaster {\n @Field(type => String, { description: 'RecipeDef[] as JSON text' })\n recipes: string\n\n @Field(type => String, { description: 'RouteDef[] as JSON text' })\n routes: string\n}\n\n@Resolver(RecipeDefinition)\nexport class RecipeQuery {\n /**\n * 레시피와 라우트를 **한 질의로** 낸다.\n *\n * 따로 물으면 그 사이에 마스터가 바뀌어 레시피가 없는 라우트를 가리키는 순간이 생긴다. 구조는\n * 서로를 가리키므로 통째로 맞아야 한다 — 마스터를 당겨 가는 다른 축과 같은 규율이다.\n */\n @Query(returns => RecipeMaster, { description: 'Recipes and routes for the twin to pull' })\n async recipeMaster(@Ctx() context: ResolverContext): Promise<RecipeMaster> {\n const { domain } = context.state\n\n const [recipes, routes] = await Promise.all([\n getRepository(RecipeDefinition).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } }),\n getRepository(RouteDefinition).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } })\n ])\n\n return {\n recipes: JSON.stringify(recipes.map(toRecipeEntry)),\n routes: JSON.stringify(routes.map(toRouteEntry))\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Domain } from '@things-factory/shell';
|
|
2
|
+
import { User } from '@things-factory/auth-base';
|
|
3
|
+
/**
|
|
4
|
+
* 라우트 — **공정을 지나는 순서**. 커널 `RouteDef` 와 같은 모양이다.
|
|
5
|
+
*
|
|
6
|
+
* ── 왜 마스터에 있나 (2026-08-31) ────────────────────────────────────────
|
|
7
|
+
* 커널에 `RouteDef` 가 있고 `JobOrder.routeKey` 가 그것을 가리키는데, **그 값이 가리킬 표가 없었다.**
|
|
8
|
+
* 사람이 문자열을 손으로 적는 상태였고, 그래서 MES 가 받은 작업지시에 라우트를 자동으로 붙일 수 없었다.
|
|
9
|
+
*
|
|
10
|
+
* 트윈 모델 JSON 에 선언하는 길도 있었는데 그러지 않은 이유가 셋이다.
|
|
11
|
+
*
|
|
12
|
+
* · **유효기간을 담을 자리가 없다.** 라우트는 개정된다. 모델에 두면 「언제부터 이 라우트였나」가 없고,
|
|
13
|
+
* 그러면 지난 실적이 **어느 라우트로 만든 것인지** 잃는다. 정산과 추적이 그 위에 선다.
|
|
14
|
+
* · **MES 가 트윈 없이 배포된다.** 라우트가 모델에 살면 MES 가 트윈을 세워야 자기 지시서를 만든다.
|
|
15
|
+
* · **표준이 그 자리에 둔다.** `OperationsDefinition` 은 Level 4·3 의 마스터이고 실행 모델이 아니다.
|
|
16
|
+
*
|
|
17
|
+
* ── 순서의 정본은 `steps` 다 ──────────────────────────────────────────────
|
|
18
|
+
* `procedure`(ISA-88 절차 계층)는 그 위에 이름을 붙이는 것이다. 트리를 따로 두면 두 곳이 어긋날 수
|
|
19
|
+
* 있고, 어긋났을 때 어느 쪽이 맞는지 말할 근거가 없다(§`RouteDef.procedure`).
|
|
20
|
+
*/
|
|
21
|
+
export declare class RouteDefinition {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
domain?: Domain;
|
|
24
|
+
domainId?: string;
|
|
25
|
+
/** 라우트 키 — 레시피와 오더가 이 값을 가리킨다(커널 `RouteDef.key`). */
|
|
26
|
+
name: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
/**
|
|
29
|
+
* 지나는 공정의 **순서** — `OperationDefinition.name` 의 목록(커널 `RouteDef.steps`).
|
|
30
|
+
*
|
|
31
|
+
* 이름으로 가리킨다. 외래키로 묶지 않는 이유는, 공정이 유효기간으로 끝나도 그것을 지나간 지난 기록이
|
|
32
|
+
* 가리킬 것을 잃지 않아야 하기 때문이다 — 마스터의 다른 축도 같은 규율이다.
|
|
33
|
+
*/
|
|
34
|
+
steps: string[];
|
|
35
|
+
/** ISA-88 절차 계층 — 선언하지 않으면 `steps` 만으로 돈다(커널 `RouteDef.procedure`). */
|
|
36
|
+
procedure?: Record<string, unknown>[];
|
|
37
|
+
/** 언제부터 유효한가 — 표준 `EffectiveStartDate`. */
|
|
38
|
+
effectiveStart?: Date;
|
|
39
|
+
/**
|
|
40
|
+
* 언제까지 유효한가 — 표준 `EffectiveEndDate`.
|
|
41
|
+
*
|
|
42
|
+
* **없앨 때 행을 지우지 않고 이 칸을 채운다.** 지우면 그것으로 만든 지난 기록이 가리킬 것을 잃는다.
|
|
43
|
+
*/
|
|
44
|
+
effectiveEnd?: Date;
|
|
45
|
+
createdAt?: Date;
|
|
46
|
+
updatedAt?: Date;
|
|
47
|
+
creator?: User;
|
|
48
|
+
creatorId?: string;
|
|
49
|
+
updater?: User;
|
|
50
|
+
updaterId?: string;
|
|
51
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RouteDefinition = 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
|
+
* 라우트 — **공정을 지나는 순서**. 커널 `RouteDef` 와 같은 모양이다.
|
|
11
|
+
*
|
|
12
|
+
* ── 왜 마스터에 있나 (2026-08-31) ────────────────────────────────────────
|
|
13
|
+
* 커널에 `RouteDef` 가 있고 `JobOrder.routeKey` 가 그것을 가리키는데, **그 값이 가리킬 표가 없었다.**
|
|
14
|
+
* 사람이 문자열을 손으로 적는 상태였고, 그래서 MES 가 받은 작업지시에 라우트를 자동으로 붙일 수 없었다.
|
|
15
|
+
*
|
|
16
|
+
* 트윈 모델 JSON 에 선언하는 길도 있었는데 그러지 않은 이유가 셋이다.
|
|
17
|
+
*
|
|
18
|
+
* · **유효기간을 담을 자리가 없다.** 라우트는 개정된다. 모델에 두면 「언제부터 이 라우트였나」가 없고,
|
|
19
|
+
* 그러면 지난 실적이 **어느 라우트로 만든 것인지** 잃는다. 정산과 추적이 그 위에 선다.
|
|
20
|
+
* · **MES 가 트윈 없이 배포된다.** 라우트가 모델에 살면 MES 가 트윈을 세워야 자기 지시서를 만든다.
|
|
21
|
+
* · **표준이 그 자리에 둔다.** `OperationsDefinition` 은 Level 4·3 의 마스터이고 실행 모델이 아니다.
|
|
22
|
+
*
|
|
23
|
+
* ── 순서의 정본은 `steps` 다 ──────────────────────────────────────────────
|
|
24
|
+
* `procedure`(ISA-88 절차 계층)는 그 위에 이름을 붙이는 것이다. 트리를 따로 두면 두 곳이 어긋날 수
|
|
25
|
+
* 있고, 어긋났을 때 어느 쪽이 맞는지 말할 근거가 없다(§`RouteDef.procedure`).
|
|
26
|
+
*/
|
|
27
|
+
let RouteDefinition = class RouteDefinition {
|
|
28
|
+
};
|
|
29
|
+
exports.RouteDefinition = RouteDefinition;
|
|
30
|
+
tslib_1.__decorate([
|
|
31
|
+
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
|
32
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.ID),
|
|
33
|
+
tslib_1.__metadata("design:type", String)
|
|
34
|
+
], RouteDefinition.prototype, "id", void 0);
|
|
35
|
+
tslib_1.__decorate([
|
|
36
|
+
(0, typeorm_1.ManyToOne)(type => shell_1.Domain),
|
|
37
|
+
(0, type_graphql_1.Field)(type => shell_1.Domain),
|
|
38
|
+
tslib_1.__metadata("design:type", shell_1.Domain)
|
|
39
|
+
], RouteDefinition.prototype, "domain", void 0);
|
|
40
|
+
tslib_1.__decorate([
|
|
41
|
+
(0, typeorm_1.RelationId)((route) => route.domain),
|
|
42
|
+
tslib_1.__metadata("design:type", String)
|
|
43
|
+
], RouteDefinition.prototype, "domainId", void 0);
|
|
44
|
+
tslib_1.__decorate([
|
|
45
|
+
(0, typeorm_1.Column)(),
|
|
46
|
+
(0, type_graphql_1.Field)(),
|
|
47
|
+
tslib_1.__metadata("design:type", String)
|
|
48
|
+
], RouteDefinition.prototype, "name", void 0);
|
|
49
|
+
tslib_1.__decorate([
|
|
50
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
51
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
52
|
+
tslib_1.__metadata("design:type", String)
|
|
53
|
+
], RouteDefinition.prototype, "description", void 0);
|
|
54
|
+
tslib_1.__decorate([
|
|
55
|
+
(0, typeorm_1.Column)({ type: 'simple-json' }),
|
|
56
|
+
(0, type_graphql_1.Field)(type => [String]),
|
|
57
|
+
tslib_1.__metadata("design:type", Array)
|
|
58
|
+
], RouteDefinition.prototype, "steps", void 0);
|
|
59
|
+
tslib_1.__decorate([
|
|
60
|
+
(0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
|
|
61
|
+
(0, type_graphql_1.Field)(type => String, { nullable: true, description: 'ProcedureElementDef[] as JSON text' }),
|
|
62
|
+
tslib_1.__metadata("design:type", Array)
|
|
63
|
+
], RouteDefinition.prototype, "procedure", void 0);
|
|
64
|
+
tslib_1.__decorate([
|
|
65
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
66
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
67
|
+
tslib_1.__metadata("design:type", Date
|
|
68
|
+
/**
|
|
69
|
+
* 언제까지 유효한가 — 표준 `EffectiveEndDate`.
|
|
70
|
+
*
|
|
71
|
+
* **없앨 때 행을 지우지 않고 이 칸을 채운다.** 지우면 그것으로 만든 지난 기록이 가리킬 것을 잃는다.
|
|
72
|
+
*/
|
|
73
|
+
)
|
|
74
|
+
], RouteDefinition.prototype, "effectiveStart", void 0);
|
|
75
|
+
tslib_1.__decorate([
|
|
76
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
77
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
78
|
+
tslib_1.__metadata("design:type", Date)
|
|
79
|
+
], RouteDefinition.prototype, "effectiveEnd", void 0);
|
|
80
|
+
tslib_1.__decorate([
|
|
81
|
+
(0, typeorm_1.CreateDateColumn)(),
|
|
82
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
83
|
+
tslib_1.__metadata("design:type", Date)
|
|
84
|
+
], RouteDefinition.prototype, "createdAt", void 0);
|
|
85
|
+
tslib_1.__decorate([
|
|
86
|
+
(0, typeorm_1.UpdateDateColumn)(),
|
|
87
|
+
(0, type_graphql_1.Field)({ nullable: true }),
|
|
88
|
+
tslib_1.__metadata("design:type", Date)
|
|
89
|
+
], RouteDefinition.prototype, "updatedAt", void 0);
|
|
90
|
+
tslib_1.__decorate([
|
|
91
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
92
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
|
|
93
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
94
|
+
], RouteDefinition.prototype, "creator", void 0);
|
|
95
|
+
tslib_1.__decorate([
|
|
96
|
+
(0, typeorm_1.RelationId)((route) => route.creator),
|
|
97
|
+
tslib_1.__metadata("design:type", String)
|
|
98
|
+
], RouteDefinition.prototype, "creatorId", void 0);
|
|
99
|
+
tslib_1.__decorate([
|
|
100
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
101
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
|
|
102
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
103
|
+
], RouteDefinition.prototype, "updater", void 0);
|
|
104
|
+
tslib_1.__decorate([
|
|
105
|
+
(0, typeorm_1.RelationId)((route) => route.updater),
|
|
106
|
+
tslib_1.__metadata("design:type", String)
|
|
107
|
+
], RouteDefinition.prototype, "updaterId", void 0);
|
|
108
|
+
exports.RouteDefinition = RouteDefinition = tslib_1.__decorate([
|
|
109
|
+
(0, typeorm_1.Entity)({ name: 'ops_route_definition' }),
|
|
110
|
+
(0, typeorm_1.Index)('ix_ops_route_definition_0', (route) => [route.domain, route.name], { unique: true }),
|
|
111
|
+
(0, type_graphql_1.ObjectType)({ description: 'Route — the ordered operations a material passes through (kernel RouteDef).' })
|
|
112
|
+
], RouteDefinition);
|
|
113
|
+
//# sourceMappingURL=route-definition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-definition.js","sourceRoot":"","sources":["../../../server/service/recipe/route-definition.ts"],"names":[],"mappings":"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","sourcesContent":["import { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, UpdateDateColumn } from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { Domain } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\n/**\n * 라우트 — **공정을 지나는 순서**. 커널 `RouteDef` 와 같은 모양이다.\n *\n * ── 왜 마스터에 있나 (2026-08-31) ────────────────────────────────────────\n * 커널에 `RouteDef` 가 있고 `JobOrder.routeKey` 가 그것을 가리키는데, **그 값이 가리킬 표가 없었다.**\n * 사람이 문자열을 손으로 적는 상태였고, 그래서 MES 가 받은 작업지시에 라우트를 자동으로 붙일 수 없었다.\n *\n * 트윈 모델 JSON 에 선언하는 길도 있었는데 그러지 않은 이유가 셋이다.\n *\n * · **유효기간을 담을 자리가 없다.** 라우트는 개정된다. 모델에 두면 「언제부터 이 라우트였나」가 없고,\n * 그러면 지난 실적이 **어느 라우트로 만든 것인지** 잃는다. 정산과 추적이 그 위에 선다.\n * · **MES 가 트윈 없이 배포된다.** 라우트가 모델에 살면 MES 가 트윈을 세워야 자기 지시서를 만든다.\n * · **표준이 그 자리에 둔다.** `OperationsDefinition` 은 Level 4·3 의 마스터이고 실행 모델이 아니다.\n *\n * ── 순서의 정본은 `steps` 다 ──────────────────────────────────────────────\n * `procedure`(ISA-88 절차 계층)는 그 위에 이름을 붙이는 것이다. 트리를 따로 두면 두 곳이 어긋날 수\n * 있고, 어긋났을 때 어느 쪽이 맞는지 말할 근거가 없다(§`RouteDef.procedure`).\n */\n@Entity({ name: 'ops_route_definition' })\n@Index('ix_ops_route_definition_0', (route: RouteDefinition) => [route.domain, route.name], { unique: true })\n@ObjectType({ description: 'Route — the ordered operations a material passes through (kernel RouteDef).' })\nexport class RouteDefinition {\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((route: RouteDefinition) => route.domain)\n domainId?: string\n\n /** 라우트 키 — 레시피와 오더가 이 값을 가리킨다(커널 `RouteDef.key`). */\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n /**\n * 지나는 공정의 **순서** — `OperationDefinition.name` 의 목록(커널 `RouteDef.steps`).\n *\n * 이름으로 가리킨다. 외래키로 묶지 않는 이유는, 공정이 유효기간으로 끝나도 그것을 지나간 지난 기록이\n * 가리킬 것을 잃지 않아야 하기 때문이다 — 마스터의 다른 축도 같은 규율이다.\n */\n @Column({ type: 'simple-json' })\n @Field(type => [String])\n steps: string[]\n\n /** ISA-88 절차 계층 — 선언하지 않으면 `steps` 만으로 돈다(커널 `RouteDef.procedure`). */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => String, { nullable: true, description: 'ProcedureElementDef[] as JSON text' })\n procedure?: Record<string, unknown>[]\n\n /** 언제부터 유효한가 — 표준 `EffectiveStartDate`. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveStart?: Date\n\n /**\n * 언제까지 유효한가 — 표준 `EffectiveEndDate`.\n *\n * **없앨 때 행을 지우지 않고 이 칸을 채운다.** 지우면 그것으로 만든 지난 기록이 가리킬 것을 잃는다.\n */\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((route: RouteDefinition) => route.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((route: RouteDefinition) => route.updater)\n updaterId?: string\n}\n"]}
|
|
@@ -26,13 +26,6 @@ export declare class MasterAxisStatus {
|
|
|
26
26
|
}
|
|
27
27
|
export declare class OpsMasterStatus {
|
|
28
28
|
axes: MasterAxisStatus[];
|
|
29
|
-
/**
|
|
30
|
-
* 우리가 맞춘 계약 판 — 읽는 쪽이 자기 판과 비교한다.
|
|
31
|
-
*
|
|
32
|
-
* 앞선 판이면 당기지 않고 말하는 것이 맞다. 반쯤 읽은 마스터로 모델을 세우면 없던 것이 「없다」로
|
|
33
|
-
* 읽히고, 그것은 오류보고없이 틀린다.
|
|
34
|
-
*/
|
|
35
|
-
contractVersion: string;
|
|
36
29
|
}
|
|
37
30
|
export declare class OpsMasterStatusQuery {
|
|
38
31
|
/**
|
|
@@ -14,8 +14,9 @@ const material_definition_1 = require("../material/material-definition");
|
|
|
14
14
|
const operation_definition_1 = require("../operation/operation-definition");
|
|
15
15
|
const person_1 = require("../personnel/person");
|
|
16
16
|
const personnel_class_1 = require("../personnel/personnel-class");
|
|
17
|
+
const recipe_definition_1 = require("../recipe/recipe-definition");
|
|
18
|
+
const route_definition_1 = require("../recipe/route-definition");
|
|
17
19
|
const test_specification_1 = require("../test-spec/test-specification");
|
|
18
|
-
const ops_contract_1 = require("@operato/ops-contract");
|
|
19
20
|
const axis_stamp_1 = require("./axis-stamp");
|
|
20
21
|
/**
|
|
21
22
|
* 축이 언제 바뀌었나 — **당길지 말지를 싸게 판단하는 자리.**
|
|
@@ -66,10 +67,6 @@ tslib_1.__decorate([
|
|
|
66
67
|
(0, type_graphql_1.Field)(type => [MasterAxisStatus]),
|
|
67
68
|
tslib_1.__metadata("design:type", Array)
|
|
68
69
|
], OpsMasterStatus.prototype, "axes", void 0);
|
|
69
|
-
tslib_1.__decorate([
|
|
70
|
-
(0, type_graphql_1.Field)({ description: 'version of @operato/ops-contract this master was written against' }),
|
|
71
|
-
tslib_1.__metadata("design:type", String)
|
|
72
|
-
], OpsMasterStatus.prototype, "contractVersion", void 0);
|
|
73
70
|
exports.OpsMasterStatus = OpsMasterStatus = tslib_1.__decorate([
|
|
74
71
|
(0, type_graphql_1.ObjectType)({ description: 'Change status of every master axis' })
|
|
75
72
|
], OpsMasterStatus);
|
|
@@ -110,9 +107,11 @@ let OpsMasterStatusQuery = class OpsMasterStatusQuery {
|
|
|
110
107
|
axisStatus('materialClasses', (0, shell_1.getRepository)(material_class_1.MaterialClass), domain.id),
|
|
111
108
|
axisStatus('materialDefinitions', (0, shell_1.getRepository)(material_definition_1.MaterialDefinition), domain.id),
|
|
112
109
|
axisStatus('operations', (0, shell_1.getRepository)(operation_definition_1.OperationDefinition), domain.id),
|
|
110
|
+
axisStatus('recipes', (0, shell_1.getRepository)(recipe_definition_1.RecipeDefinition), domain.id),
|
|
111
|
+
axisStatus('routes', (0, shell_1.getRepository)(route_definition_1.RouteDefinition), domain.id),
|
|
113
112
|
axisStatus('testSpecifications', (0, shell_1.getRepository)(test_specification_1.TestSpecification), domain.id)
|
|
114
113
|
]);
|
|
115
|
-
return { axes
|
|
114
|
+
return { axes };
|
|
116
115
|
}
|
|
117
116
|
};
|
|
118
117
|
exports.OpsMasterStatusQuery = OpsMasterStatusQuery;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-status.js","sourceRoot":"","sources":["../../../server/service/status/master-status.ts"],"names":[],"mappings":";;;;AAAA,+CAA2E;AAG3E,iDAAqD;AAErD,4DAAuD;AACvD,wEAAkE;AAClE,sDAAkD;AAClD,kEAA6D;AAC7D,2EAAsE;AACtE,+DAA0D;AAC1D,yEAAoE;AACpE,4EAAuE;AACvE,gDAA4C;AAC5C,kEAA6D;AAC7D,
|
|
1
|
+
{"version":3,"file":"master-status.js","sourceRoot":"","sources":["../../../server/service/status/master-status.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ctx, Field, Int, ObjectType, Query, Resolver } from 'type-graphql'\nimport type { ObjectLiteral, Repository } from 'typeorm'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { PhysicalAsset } from '../asset/physical-asset'\nimport { PhysicalAssetClass } from '../asset/physical-asset-class'\nimport { Equipment } from '../equipment/equipment'\nimport { EquipmentClass } from '../equipment/equipment-class'\nimport { OperationalLocation } from '../location/operational-location'\nimport { MaterialClass } from '../material/material-class'\nimport { MaterialDefinition } from '../material/material-definition'\nimport { OperationDefinition } from '../operation/operation-definition'\nimport { Person } from '../personnel/person'\nimport { PersonnelClass } from '../personnel/personnel-class'\nimport { RecipeDefinition } from '../recipe/recipe-definition'\nimport { RouteDefinition } from '../recipe/route-definition'\nimport { TestSpecification } from '../test-spec/test-specification'\n\nimport { axisStamp } from './axis-stamp'\n\n/**\n * 축이 언제 바뀌었나 — **당길지 말지를 싸게 판단하는 자리.**\n *\n * ── 왜 필요한가 ─────────────────────────────────────────────────────────────\n * 트윈은 마스터를 주기적으로 당긴다. 그런데 인원 마스터가 수천 건이면 바뀐 것이 없어도 매번 그만큼을\n * 옮기게 된다. 이 질의는 **축마다 마지막으로 바뀐 시각과 건수만** 내므로, 트윈이 자기가 마지막으로 본\n * 값과 비교해 바뀐 축만 당길 수 있다.\n *\n * ── 왜 지우지 않는가 ────────────────────────────────────────────────────────\n * 건수가 줄지 않는 것을 전제로 한다. 마스터에서 무엇을 「없앨」 때 행을 지우지 않고 유효 기간으로\n * 끝내기 때문이다(§`effectiveEnd`). 지우면 그 개체를 가리키는 지난 기록이 가리킬 것을 잃는다.\n */\n@ObjectType({ description: 'When one master axis last changed' })\nexport class MasterAxisStatus {\n @Field({ description: 'axis name, matching the pull query' })\n axis: string\n\n @Field(type => Int, { description: 'number of rows in this axis' })\n count: number\n\n /** 마지막으로 바뀐 시각. 축이 비어 있으면 없다 — 「비어 있다」와 「바뀐 적 없다」를 섞지 않는다. */\n @Field({ nullable: true, description: 'last change time, absent when the axis is empty' })\n changedAt?: Date\n\n /**\n * 이 축의 상태를 대표하는 값 하나 — **크기로 비교하지 말고 같은지만 본다.**\n *\n * 시각을 크기로 비교하면 시계가 되감길 때(백업 복원 · 시각 보정) 바뀐 것을 놓친다. 개수를 함께 담아\n * 두므로 같은 초에 두 번 바뀌어도 표시가 달라진다. 읽는 쪽은 자기가 마지막으로 본 표시와 **다르면**\n * 당기면 된다.\n */\n @Field({ description: 'opaque value — compare for equality, never for order' })\n stamp: string\n}\n\n@ObjectType({ description: 'Change status of every master axis' })\nexport class OpsMasterStatus {\n @Field(type => [MasterAxisStatus])\n axes: MasterAxisStatus[]\n\n}\n\n/** 축 하나의 건수와 마지막 변경 시각. 두 값을 한 질의로 읽는다. */\nasync function axisStatus<T extends ObjectLiteral>(\n axis: string,\n repository: Repository<T>,\n domainId: string\n): Promise<MasterAxisStatus> {\n const row = await repository\n .createQueryBuilder('row')\n .select('COUNT(1)', 'count')\n .addSelect('MAX(row.updatedAt)', 'changedAt')\n .where('row.domain = :domainId', { domainId })\n .getRawOne<{ count: string | number; changedAt: Date | string | null }>()\n\n const count = Number(row?.count ?? 0)\n const changedAt = row?.changedAt ? new Date(row.changedAt) : undefined\n\n return {\n axis,\n count,\n stamp: axisStamp(count, changedAt),\n ...(changedAt ? { changedAt } : {})\n }\n}\n\n\n@Resolver(OpsMasterStatus)\nexport class OpsMasterStatusQuery {\n /**\n * 모든 축의 변경 상태 — 트윈이 주기적으로 부르는 자리.\n *\n * 한 번에 낸다. 축마다 따로 물으면 일곱 번 오가고, 그 사이에 마스터가 바뀌면 축들이 서로 다른 시점을\n * 보게 된다.\n */\n @Query(returns => OpsMasterStatus, { description: 'Change status of every master axis' })\n async opsMasterStatus(@Ctx() context: ResolverContext): Promise<OpsMasterStatus> {\n const { domain } = context.state\n\n const axes = await Promise.all([\n axisStatus('personnelClasses', getRepository(PersonnelClass), domain.id),\n axisStatus('persons', getRepository(Person), domain.id),\n axisStatus('equipmentClasses', getRepository(EquipmentClass), domain.id),\n axisStatus('equipment', getRepository(Equipment), domain.id),\n axisStatus('assetClasses', getRepository(PhysicalAssetClass), domain.id),\n axisStatus('assets', getRepository(PhysicalAsset), domain.id),\n axisStatus('locations', getRepository(OperationalLocation), domain.id),\n axisStatus('materialClasses', getRepository(MaterialClass), domain.id),\n axisStatus('materialDefinitions', getRepository(MaterialDefinition), domain.id),\n axisStatus('operations', getRepository(OperationDefinition), domain.id),\n axisStatus('recipes', getRepository(RecipeDefinition), domain.id),\n axisStatus('routes', getRepository(RouteDefinition), domain.id),\n axisStatus('testSpecifications', getRepository(TestSpecification), domain.id)\n ])\n\n return { axes }\n }\n}\n"]}
|