@things-factory/ops-master 10.1.47 → 10.1.81
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/revision-workspace.js +32 -25
- package/dist-client/pages/master/revision-workspace.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/asset/index.d.ts +2 -2
- package/dist-server/service/equipment/index.d.ts +2 -2
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/service/location/index.d.ts +1 -1
- package/dist-server/service/master-change-policy.d.ts +30 -3
- package/dist-server/service/master-change-policy.js +7 -3
- package/dist-server/service/master-change-policy.js.map +1 -1
- package/dist-server/service/material/index.d.ts +1 -1
- package/dist-server/service/material/material-revision-resolver.d.ts +1 -1
- package/dist-server/service/material/material-revision-resolver.js +6 -4
- package/dist-server/service/material/material-revision-resolver.js.map +1 -1
- package/dist-server/service/material/material-revision-service.d.ts +2 -0
- package/dist-server/service/material/material-revision-service.js +6 -1
- package/dist-server/service/material/material-revision-service.js.map +1 -1
- package/dist-server/service/operation/index.d.ts +1 -1
- package/dist-server/service/personnel/index.d.ts +2 -2
- package/dist-server/service/recipe/index.d.ts +2 -2
- package/dist-server/service/recipe/recipe-revision-resolver.d.ts +1 -1
- package/dist-server/service/recipe/recipe-revision-resolver.js +6 -4
- package/dist-server/service/recipe/recipe-revision-resolver.js.map +1 -1
- package/dist-server/service/recipe/recipe-revision-service.d.ts +2 -0
- package/dist-server/service/recipe/recipe-revision-service.js +6 -1
- package/dist-server/service/recipe/recipe-revision-service.js.map +1 -1
- package/dist-server/service/recipe/recipe-revision.d.ts +1 -1
- package/dist-server/service/test-spec/index.d.ts +1 -1
- package/dist-server/service/test-spec/test-spec-revision-resolver.d.ts +1 -1
- package/dist-server/service/test-spec/test-spec-revision-resolver.js +6 -4
- package/dist-server/service/test-spec/test-spec-revision-resolver.js.map +1 -1
- package/dist-server/service/test-spec/test-spec-revision-service.d.ts +2 -0
- package/dist-server/service/test-spec/test-spec-revision-service.js +6 -1
- package/dist-server/service/test-spec/test-spec-revision-service.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -2,5 +2,5 @@ import { AssetQuery } from './asset-query';
|
|
|
2
2
|
import { PhysicalAsset } from './physical-asset';
|
|
3
3
|
import { PhysicalAssetClass } from './physical-asset-class';
|
|
4
4
|
import { PhysicalAssetClassResolver, PhysicalAssetResolver } from './asset-master-resolver';
|
|
5
|
-
export declare const entities: (typeof
|
|
6
|
-
export declare const resolvers: (typeof
|
|
5
|
+
export declare const entities: (typeof PhysicalAsset | typeof PhysicalAssetClass)[];
|
|
6
|
+
export declare const resolvers: (typeof PhysicalAssetClassResolver | typeof PhysicalAssetResolver | typeof AssetQuery)[];
|
|
@@ -4,5 +4,5 @@ import { EquipmentQuery } from './equipment-query';
|
|
|
4
4
|
import { StopReason } from './stop-reason';
|
|
5
5
|
import { StopReasonQuery } from './stop-reason-query';
|
|
6
6
|
import { EquipmentClassResolver, EquipmentResolver, StopReasonResolver } from './equipment-master-resolver';
|
|
7
|
-
export declare const entities: (typeof
|
|
8
|
-
export declare const resolvers: (typeof
|
|
7
|
+
export declare const entities: (typeof Equipment | typeof EquipmentClass | typeof StopReason)[];
|
|
8
|
+
export declare const resolvers: (typeof EquipmentClassResolver | typeof EquipmentResolver | typeof StopReasonResolver | typeof EquipmentQuery | typeof StopReasonQuery)[];
|
|
@@ -70,9 +70,9 @@ export * from './quality/nonconformance-cause';
|
|
|
70
70
|
import { MasterConformanceResolver } from './master-conformance-resolver';
|
|
71
71
|
import { MasterChangePolicy, MasterChangePolicyResolver } from './master-change-policy';
|
|
72
72
|
import { MasterValueClaim } from './assignment/master-value-claim';
|
|
73
|
-
export declare const entities: (typeof
|
|
73
|
+
export declare const entities: (typeof import("./equipment/equipment").Equipment | typeof import("./equipment/equipment-class").EquipmentClass | typeof import("./quality/nonconformance-cause").NonconformanceCause | typeof import("./material/material-definition").MaterialDefinition | typeof import("./operation/operation-definition").OperationDefinition | typeof import("./location/operational-location").OperationalLocation | typeof import("./personnel/person").Person | typeof import("./asset/physical-asset").PhysicalAsset | typeof import("./recipe").RecipeDefinition | typeof import("./recipe").RouteDefinition | typeof import("./test-spec/test-specification").TestSpecification | typeof MasterChangePolicy | typeof import("./material/material-revision").MaterialDefinitionRevision | typeof import("./material/material-revision").MaterialDefinitionPlan | typeof import("./material/material-revision").MaterialDefinitionSegment | typeof import("./material/material-revision").MaterialDefinitionBasis | typeof import("./recipe/recipe-revision").RecipeRevision | typeof import("./recipe/recipe-revision-line").RecipeRevisionOutput | typeof import("./recipe/recipe-revision").RecipePlan | typeof import("./recipe/recipe-revision").RecipeSegment | typeof import("./recipe/recipe-revision").RecipeBasis | typeof import("./test-spec/test-spec-revision").TestSpecificationRevision | typeof import("./test-spec/test-spec-revision").TestSpecificationPlan | typeof import("./test-spec/test-spec-revision").TestSpecificationSegment | typeof import("./test-spec/test-spec-revision").TestSpecificationBasis | typeof MasterValueClaim)[];
|
|
74
74
|
export declare const schema: {
|
|
75
|
-
resolverClasses: (typeof MasterChangePolicyResolver | typeof import("./personnel/personnel-
|
|
75
|
+
resolverClasses: (typeof MasterChangePolicyResolver | typeof import("./personnel/personnel-master-resolver").PersonnelClassResolver | typeof import("./personnel/personnel-master-resolver").PersonResolver | typeof import("./equipment/equipment-master-resolver").EquipmentClassResolver | typeof import("./equipment/equipment-master-resolver").EquipmentResolver | typeof import("./equipment/equipment-master-resolver").StopReasonResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetClassResolver | typeof import("./asset/asset-master-resolver").PhysicalAssetResolver | typeof import("./material/material-master-resolver").MaterialClassResolver | typeof import("./material/material-master-resolver").MaterialDefinitionResolver | typeof import("./location/location-master-resolver").OperationalLocationResolver | typeof import("./operation/operation-master-resolver").OperationDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RecipeDefinitionResolver | typeof import("./recipe/recipe-master-resolver").RouteDefinitionResolver | typeof import("./test-spec/test-spec-master-resolver").TestSpecificationResolver | typeof MasterConformanceResolver | typeof import("./personnel/personnel-query").PersonnelQuery | typeof import("./equipment/equipment-query").EquipmentQuery | typeof import("./asset/asset-query").AssetQuery | typeof import("./location/location-query").LocationQuery | typeof import("./material/material-revision-resolver").MaterialDefinitionRevisionResolver | typeof import("./material/material-query").MaterialQuery | typeof import("./operation/operation-query").OperationQuery | typeof import("./operation/operation-readiness-resolver").OperationReadinessResolver | typeof import("./recipe/recipe-revision-resolver").RecipeRevisionResolver | typeof import("./recipe/recipe-query").RecipeQuery | typeof import("./test-spec/test-spec-revision-resolver").TestSpecificationRevisionResolver | typeof import("./test-spec/test-spec-query").TestSpecificationQuery | typeof import("./status/master-status").OpsMasterStatusQuery | typeof import("./equipment/stop-reason-query").StopReasonQuery | typeof import("./quality/nonconformance-cause-resolver").NonconformanceCauseResolver)[];
|
|
76
76
|
};
|
|
77
77
|
export * from './assignment/master-value-claim';
|
|
78
78
|
export * from './assignment/assignment-history';
|
|
@@ -2,4 +2,4 @@ import { LocationQuery } from './location-query';
|
|
|
2
2
|
import { OperationalLocation } from './operational-location';
|
|
3
3
|
import { OperationalLocationResolver } from './location-master-resolver';
|
|
4
4
|
export declare const entities: (typeof OperationalLocation)[];
|
|
5
|
-
export declare const resolvers: (typeof
|
|
5
|
+
export declare const resolvers: (typeof OperationalLocationResolver | typeof LocationQuery)[];
|
|
@@ -67,12 +67,39 @@ export declare function standingPolicies(manager: EntityManager, domainId: strin
|
|
|
67
67
|
export declare function declareMasterChangePolicy(manager: EntityManager, domainId: string, actorId: string, axis: string, approvalRequired: boolean, reason: string): Promise<MasterChangePolicy>;
|
|
68
68
|
export declare function assertDirectMasterChange(manager: EntityManager, domainId: string, axis: string): Promise<void>;
|
|
69
69
|
export declare class MasterChangePolicyResolver {
|
|
70
|
-
masterChangePolicy(axis: string, context: ResolverContext): Promise<
|
|
70
|
+
masterChangePolicy(axis: string, context: ResolverContext): Promise<{
|
|
71
|
+
declared: boolean;
|
|
72
|
+
id: string;
|
|
73
|
+
domain: Domain;
|
|
74
|
+
domainId: string;
|
|
75
|
+
axis: string;
|
|
76
|
+
approvalRequired: boolean;
|
|
77
|
+
reason: string;
|
|
78
|
+
/**
|
|
79
|
+
* 이 줄이 물러난 시각 — 비어 있는 줄이 **지금 정책**이다.
|
|
80
|
+
*
|
|
81
|
+
* 차례를 `createdAt` 으로 세우지 않는다. sqlite 의 `datetime('now')` 는 초까지라, 한 사람이 같은
|
|
82
|
+
* 초에 두 번 바꾸면 어느 줄이 나중인지 저장소가 못 가린다. 물러난 줄에 표를 하면 그 물음이 사라진다.
|
|
83
|
+
*/
|
|
84
|
+
supersededAt: Date;
|
|
85
|
+
/**
|
|
86
|
+
* 누가 정했나 — **비어 있으면 아무도 안 정한 것**이고, 그 줄은 기본값으로 선 줄이다.
|
|
87
|
+
*
|
|
88
|
+
* 사람이 안 정한 줄에 사람을 적으면 그 사람이 정한 것이 된다. 사업장을 만든 사람도 이 축을 보고
|
|
89
|
+
* 고른 적이 없다.
|
|
90
|
+
*/
|
|
91
|
+
creator: User;
|
|
92
|
+
creatorId: string;
|
|
93
|
+
createdAt: Date;
|
|
94
|
+
} | {
|
|
95
|
+
axis: string;
|
|
96
|
+
declared: boolean;
|
|
97
|
+
approvalRequired: boolean;
|
|
98
|
+
}>;
|
|
71
99
|
/**
|
|
72
100
|
* 축 전부의 정책 상태 — **안 정한 것도 답한다.**
|
|
73
101
|
*
|
|
74
|
-
*
|
|
75
|
-
* **정하러 들어가는 화면까지 막는다.** 그래서 목록은 따로 둔다 — 안 정한 축은 안 정했다고 답한다.
|
|
102
|
+
* 단일 조회처럼 안 정한 축은 기본값과 미선언 상태를 답한다. 목록에는 관리 권한과 결재 경로 상태도 담는다.
|
|
76
103
|
*
|
|
77
104
|
* `canDeclare` 는 **이 사람이 소유자인가**다. 화면이 스스로 판단하지 않게 서버가 말한다 —
|
|
78
105
|
* 눌러 보고 거절당하는 화면이 되지 않도록.
|
|
@@ -214,13 +214,17 @@ async function assertDirectMasterChange(manager, domainId, axis) {
|
|
|
214
214
|
let MasterChangePolicyResolver = class MasterChangePolicyResolver {
|
|
215
215
|
async masterChangePolicy(axis, context) {
|
|
216
216
|
/* 읽기만 하는 자리다. 안 정한 축에 줄을 세우지 않는다 — 그것은 고치러 들어간 쪽이 할 일이다. */
|
|
217
|
-
|
|
217
|
+
policyAxis(axis);
|
|
218
|
+
const policy = await standingPolicy((0, shell_1.getRepository)(MasterChangePolicy).manager, context.state.domain.id, axis);
|
|
219
|
+
// A fresh site's editor must see the same default the first write will use, without inventing a policy id.
|
|
220
|
+
return policy
|
|
221
|
+
? { ...policy, declared: true }
|
|
222
|
+
: { axis, declared: false, approvalRequired: exports.DEFAULT_APPROVAL_REQUIRED };
|
|
218
223
|
}
|
|
219
224
|
/**
|
|
220
225
|
* 축 전부의 정책 상태 — **안 정한 것도 답한다.**
|
|
221
226
|
*
|
|
222
|
-
*
|
|
223
|
-
* **정하러 들어가는 화면까지 막는다.** 그래서 목록은 따로 둔다 — 안 정한 축은 안 정했다고 답한다.
|
|
227
|
+
* 단일 조회처럼 안 정한 축은 기본값과 미선언 상태를 답한다. 목록에는 관리 권한과 결재 경로 상태도 담는다.
|
|
224
228
|
*
|
|
225
229
|
* `canDeclare` 는 **이 사람이 소유자인가**다. 화면이 스스로 판단하지 않게 서버가 말한다 —
|
|
226
230
|
* 눌러 보고 거절당하는 화면이 되지 않도록.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-change-policy.js","sourceRoot":"","sources":["../../server/service/master-change-policy.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n Entity,\n EntityManager,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId\n} from 'typeorm'\nimport { IsNull } from 'typeorm'\nimport { Arg, Ctx, Directive, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql'\nimport { Domain, getRepository, Refusal, ScalarObject, SpeakRefusals } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { MASTER_AXES, masterAxisOf } from './master-axis'\nimport { assertApprovalRouteReady, inspectApprovalRoute } from './approval-route'\n\n// WorkShift owns a domain-wide arrangement, not a row in the generic master CRUD registry.\nfunction policyAxis(axis: string) {\n if (axis !== 'workShift') masterAxisOf(axis)\n}\n\n/**\n * 정책을 정할 수 있는 축들 — 마스터 축 열다섯에 `workShift` 를 더한다.\n *\n * `workShift` 는 별도 모듈이라 `MASTER_AXES` 에 없는데 정책은 받는다(§`policyAxis`).\n */\nexport const POLICY_AXES = [...MASTER_AXES.map(one => one.key), 'workShift']\n\n/**\n * 이 축의 바뀜을 **개정본으로 결재에 보낼 수 있나** — 승인으로 켤 수 있는 축인가.\n *\n * 마스터 축은 자기 선언(`MasterAxis.revisable`)이 답한다. `workShift` 는 그 표 밖에서 자기 꾸러미가\n * 개정 체계를 지었으므로 참이다(`work-shift-revision-service`). 앱이 답하지 않는다 — 문이 없으면\n * 어느 앱에서도 보낼 곳이 없다.\n */\nexport function axisHasRevision(axis: string): boolean {\n if (axis === 'workShift') return true\n return masterAxisOf(axis).revisable\n}\n\n/** 도메인 × 축의 기준정보 변경 정책 — 정하는 것도 바꾸는 것도 사업장 소유자의 몫이다. */\n@Entity('ops_master_change_policy')\n/*\n * 도메인 × 축에 **줄이 여럿 선다.** 정책은 바뀌고, 바뀌면 새 줄이 서고, 지난 개정본은 자기가 만들어질\n * 때의 줄을 그대로 가리킨다 — 그래야 「그때는 무슨 규칙이었나」가 안 흔들린다.\n *\n * 전에는 유니크였다. 그래서 바꾸려면 그 줄을 덮어야 했고, 덮으면 승인받고 만든 개정본이 소급해서\n * 승인 없이 만든 것이 됐다. 그래서 코드가 바꾸기를 거절했고, **정책을 영영 못 바꿨다.**\n *\n * ⚠ **이 정책을 바꾸는 일 자체는 결재에 안 태운다**(2026-09-22). 사업장 소유자가 정하는 것이라\n * 소유자 확인만 받고 바로 선다. 태울 필요가 생기면 그때 결재 활동을 붙인다 — 줄이 여럿 서는\n * 구조라 붙이는 자리는 이미 있다.\n */\n@Index('ix_master_change_policy_axis', ['domain', 'axis'])\n@Index('ix_master_change_policy_identity', ['domain', 'id'], { unique: true })\nexport class MasterChangePolicy {\n @PrimaryGeneratedColumn('uuid') id: string\n @ManyToOne(() => Domain, { nullable: false }) domain: Domain\n @RelationId((row: MasterChangePolicy) => row.domain) domainId: string\n @Column() axis: string\n @Column() approvalRequired: boolean\n @Column('text') reason: string\n /**\n * 이 줄이 물러난 시각 — 비어 있는 줄이 **지금 정책**이다.\n *\n * 차례를 `createdAt` 으로 세우지 않는다. sqlite 의 `datetime('now')` 는 초까지라, 한 사람이 같은\n * 초에 두 번 바꾸면 어느 줄이 나중인지 저장소가 못 가린다. 물러난 줄에 표를 하면 그 물음이 사라진다.\n */\n @Column({ nullable: true }) supersededAt: Date\n /**\n * 누가 정했나 — **비어 있으면 아무도 안 정한 것**이고, 그 줄은 기본값으로 선 줄이다.\n *\n * 사람이 안 정한 줄에 사람을 적으면 그 사람이 정한 것이 된다. 사업장을 만든 사람도 이 축을 보고\n * 고른 적이 없다.\n */\n @ManyToOne(() => User, { nullable: true }) creator: User\n @RelationId((row: MasterChangePolicy) => row.creator) creatorId: string\n @CreateDateColumn() createdAt: Date\n}\n\n/** 아무도 안 정한 축이 도는 방식 — 바꾸려면 여기 하나만 고치면 된다. */\nexport const DEFAULT_APPROVAL_REQUIRED = false\n\n/**\n * 이 축이 지금 어떻게 도는가. **아무도 안 정했으면 기본값으로 한 줄을 세우고 그것을 답한다.**\n *\n * 전에는 거절했다(`MASTER_POLICY_REQUIRED`). 그래서 새 사업장은 축 열여섯이 전부 막힌 채로 시작했고,\n * 기준정보를 만들려던 사람이 「정책을 먼저 정하라」는 말만 받았다 — 어디서 정하는지는 안 적혀 있었다.\n *\n * 값을 그때그때 지어내지 않고 **줄을 세우는** 까닭은, 개정본이 자기가 어느 정책 아래 만들어졌는지를\n * 그 줄로 가리키기 때문이다(ADR-0090). 가리킬 줄이 없으면 그 물음에 나중에 답할 수 없다.\n *\n * 그 줄의 `creator` 는 비어 있다. 아무도 고른 적이 없다는 것이 사실이고, 사업장을 만든 사람을 적으면\n * 그 사람이 정한 것이 된다.\n */\nexport async function masterChangePolicy(manager: EntityManager, domainId: string, axis: string) {\n policyAxis(axis)\n const policy = await standingPolicy(manager, domainId, axis)\n if (policy) {\n return policy\n }\n\n if (!manager.queryRunner?.isTransactionActive)\n throw new Refusal('TRANSACTION_REQUIRED', {}, 'A transaction is required.')\n\n return manager.save(\n MasterChangePolicy,\n manager.create(MasterChangePolicy, {\n domain: { id: domainId },\n axis,\n approvalRequired: DEFAULT_APPROVAL_REQUIRED,\n reason: 'nobody set this axis; it runs on the default'\n })\n )\n}\n\n/** 이 축에서 물러나지 않은 줄 전부 — 보통 하나다. */\nfunction standingRows(manager: EntityManager, domainId: string, axis: string) {\n return manager.findBy(MasterChangePolicy, { domain: { id: domainId }, axis, supersededAt: IsNull() })\n}\n\n/**\n * 지금 서 있는 줄.\n *\n * 둘 이상이 서 있으면 **가장 늦게 만들어진 것**을 답한다. 그 상태는 이 코드가 못 만들지만, 물러남\n * 표를 두기 전에 쌓인 줄들이 그렇게 남아 있다. 다음 선언이 전부 물러나게 하고 하나로 정리한다.\n */\nexport async function standingPolicy(manager: EntityManager, domainId: string, axis: string) {\n const rows = await standingRows(manager, domainId, axis)\n\n return rows.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()).pop() ?? null\n}\n\n/** 이 도메인에서 지금 서 있는 줄 전부 — 축을 열쇠로. */\nexport async function standingPolicies(manager: EntityManager, domainId: string) {\n const rows = await manager.findBy(MasterChangePolicy, { domain: { id: domainId }, supersededAt: IsNull() })\n\n /* 이른 것부터 담아서 같은 축은 늦은 것이 이긴다 — `standingPolicy` 와 같은 답이 되도록. */\n rows.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime())\n\n return new Map(rows.map(one => [one.axis, one]))\n}\n\nexport async function declareMasterChangePolicy(\n manager: EntityManager,\n domainId: string,\n actorId: string,\n axis: string,\n approvalRequired: boolean,\n reason: string\n) {\n if (!manager.queryRunner?.isTransactionActive)\n throw new Refusal('TRANSACTION_REQUIRED', {}, 'A transaction is required.')\n policyAxis(axis)\n const domain = await manager.findOneByOrFail(Domain, { id: domainId })\n if (domain.owner !== actorId)\n throw new Refusal(\n 'MASTER_POLICY_OWNER_REQUIRED',\n {},\n 'Only the domain owner may declare or change the master change policy.'\n )\n if (!reason?.trim()) throw new Refusal('MASTER_POLICY_REASON_REQUIRED', {}, 'Explain the policy declaration.')\n\n /*\n * 규제를 **거는** 쪽만 본다. 푸는 쪽은 결재선이 비어 있어도 되고, 오히려 비어서 멈춘 축을 푸는 것이\n * 이 화면으로 할 수 있는 일이어야 한다.\n */\n if (approvalRequired) {\n /*\n * 개정본 문이 없는 축은 **켜는 것부터 막는다**(2026-09-24). 켜면 직접 쓰기가 전부 거절되는데 결재로\n * 보낼 곳이 없어서 그 축이 통째로 잠긴다. 결재선을 묻기 전에 본다 — 결재선이 있어도 보낼 문이 없다.\n */\n if (!axisHasRevision(axis))\n throw new Refusal(\n 'MASTER_AXIS_HAS_NO_REVISION',\n { axis },\n 'This master cannot be sent for approval yet, so it cannot be set to change only after approval.'\n )\n await assertApprovalRouteReady(manager, domainId, axis)\n }\n\n const standing = await standingRows(manager, domainId, axis)\n\n /*\n * 같은 값을 다시 정하는 것은 아무 일도 아니다 — **하나만 서 있을 때** 그렇다. 여럿이 서 있으면\n * 어느 것이 지금 것인지가 안 정해진 상태이므로, 값이 같아 보여도 전부 물리고 하나로 다시 세운다.\n */\n if (standing.length === 1 && standing[0].approvalRequired === approvalRequired) {\n return standing[0]\n }\n\n const supersededAt = new Date()\n for (const row of standing) {\n row.supersededAt = supersededAt\n await manager.save(MasterChangePolicy, row)\n }\n\n /*\n * 바뀌면 **새 줄을 세운다. 있던 줄은 그대로 둔다.**\n *\n * 지난 개정본들이 그 줄을 가리키고 있다(`RecipeRevision.policy`, RESTRICT). 덮으면 그것들이\n * 소급해서 다른 규칙 아래 만들어진 것이 된다 — 그래서 덮지 않고 새로 세운다. 오늘부터는 새 줄이\n * 현재 정책이고, 지난 것은 자기 때의 줄을 계속 가리킨다.\n */\n return manager.save(\n MasterChangePolicy,\n manager.create(MasterChangePolicy, {\n domain: { id: domainId },\n axis,\n approvalRequired,\n reason,\n creator: { id: actorId }\n })\n )\n}\n\nexport async function assertDirectMasterChange(manager: EntityManager, domainId: string, axis: string) {\n const policy = await standingPolicy(manager, domainId, axis)\n if (policy?.approvalRequired)\n throw new Refusal('MASTER_APPROVAL_REQUIRED', { axis }, 'This master axis requires approval in this domain.')\n}\n\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class MasterChangePolicyResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(() => ScalarObject)\n async masterChangePolicy(@Arg('axis') axis: string, @Ctx() context: ResolverContext) {\n /* 읽기만 하는 자리다. 안 정한 축에 줄을 세우지 않는다 — 그것은 고치러 들어간 쪽이 할 일이다. */\n return standingPolicy(getRepository(MasterChangePolicy).manager, context.state.domain.id, axis)\n }\n\n /**\n * 축 전부의 정책 상태 — **안 정한 것도 답한다.**\n *\n * `masterChangePolicy` 는 안 정했으면 거절한다. 그것은 「고치기 전에 정해라」를 말하는 자리라 맞지만,\n * **정하러 들어가는 화면까지 막는다.** 그래서 목록은 따로 둔다 — 안 정한 축은 안 정했다고 답한다.\n *\n * `canDeclare` 는 **이 사람이 소유자인가**다. 화면이 스스로 판단하지 않게 서버가 말한다 —\n * 눌러 보고 거절당하는 화면이 되지 않도록.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(() => ScalarObject)\n async masterChangePolicies(@Ctx() context: ResolverContext) {\n const { domain, user } = context.state\n const manager = getRepository(MasterChangePolicy).manager\n /*\n * **물러나지 않은 줄만** 읽는다. 축마다 줄이 여럿이라, 전부 담으면 저장소가 주는 차례대로 덮여서\n * 바꾼 뒤에도 화면에 옛 값이 떴다(2026-09-22 화면에서 확인).\n */\n const byAxis = await standingPolicies(manager, domain.id)\n\n return {\n canDeclare: domain.owner === user?.id,\n axes: await Promise.all(\n POLICY_AXES.map(async axis => {\n const policy = byAxis.get(axis)\n /*\n * 결재 길이 준비됐나 — **화면이 누르기 전에 알아야 한다.** 답이 없는 축은 이 앱이 아직 이\n * 물음에 답할 길이 없다는 뜻이라 막지 않는다(`inspectApprovalRoute`).\n */\n const route = await inspectApprovalRoute(manager, domain.id, axis)\n\n return {\n axis,\n declared: !!policy,\n /* 줄은 섰지만 사람이 고른 적은 없다 — 화면이 그것을 다르게 보인다. */\n byDefault: !!policy && !policy.creatorId,\n approvalRequired: policy?.approvalRequired ?? null,\n reason: policy?.reason ?? null,\n declaredAt: policy?.createdAt ?? null,\n /* 승인으로 켤 수 있는 축인가 — 아니면 화면은 누르기 전에 그 까닭을 말한다. */\n revisable: axisHasRevision(axis),\n approvalReady: route ? route.ready : true,\n approvalActivity: route?.activity ?? null\n }\n })\n )\n }\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async declareMasterChangePolicy(\n @Arg('axis') axis: string,\n @Arg('approvalRequired') approvalRequired: boolean,\n @Arg('reason') reason: string,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return declareMasterChangePolicy(tx, domain.id, user.id, axis, approvalRequired, reason)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"master-change-policy.js","sourceRoot":"","sources":["../../server/service/master-change-policy.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n Entity,\n EntityManager,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId\n} from 'typeorm'\nimport { IsNull } from 'typeorm'\nimport { Arg, Ctx, Directive, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql'\nimport { Domain, getRepository, Refusal, ScalarObject, SpeakRefusals } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { MASTER_AXES, masterAxisOf } from './master-axis'\nimport { assertApprovalRouteReady, inspectApprovalRoute } from './approval-route'\n\n// WorkShift owns a domain-wide arrangement, not a row in the generic master CRUD registry.\nfunction policyAxis(axis: string) {\n if (axis !== 'workShift') masterAxisOf(axis)\n}\n\n/**\n * 정책을 정할 수 있는 축들 — 마스터 축 열다섯에 `workShift` 를 더한다.\n *\n * `workShift` 는 별도 모듈이라 `MASTER_AXES` 에 없는데 정책은 받는다(§`policyAxis`).\n */\nexport const POLICY_AXES = [...MASTER_AXES.map(one => one.key), 'workShift']\n\n/**\n * 이 축의 바뀜을 **개정본으로 결재에 보낼 수 있나** — 승인으로 켤 수 있는 축인가.\n *\n * 마스터 축은 자기 선언(`MasterAxis.revisable`)이 답한다. `workShift` 는 그 표 밖에서 자기 꾸러미가\n * 개정 체계를 지었으므로 참이다(`work-shift-revision-service`). 앱이 답하지 않는다 — 문이 없으면\n * 어느 앱에서도 보낼 곳이 없다.\n */\nexport function axisHasRevision(axis: string): boolean {\n if (axis === 'workShift') return true\n return masterAxisOf(axis).revisable\n}\n\n/** 도메인 × 축의 기준정보 변경 정책 — 정하는 것도 바꾸는 것도 사업장 소유자의 몫이다. */\n@Entity('ops_master_change_policy')\n/*\n * 도메인 × 축에 **줄이 여럿 선다.** 정책은 바뀌고, 바뀌면 새 줄이 서고, 지난 개정본은 자기가 만들어질\n * 때의 줄을 그대로 가리킨다 — 그래야 「그때는 무슨 규칙이었나」가 안 흔들린다.\n *\n * 전에는 유니크였다. 그래서 바꾸려면 그 줄을 덮어야 했고, 덮으면 승인받고 만든 개정본이 소급해서\n * 승인 없이 만든 것이 됐다. 그래서 코드가 바꾸기를 거절했고, **정책을 영영 못 바꿨다.**\n *\n * ⚠ **이 정책을 바꾸는 일 자체는 결재에 안 태운다**(2026-09-22). 사업장 소유자가 정하는 것이라\n * 소유자 확인만 받고 바로 선다. 태울 필요가 생기면 그때 결재 활동을 붙인다 — 줄이 여럿 서는\n * 구조라 붙이는 자리는 이미 있다.\n */\n@Index('ix_master_change_policy_axis', ['domain', 'axis'])\n@Index('ix_master_change_policy_identity', ['domain', 'id'], { unique: true })\nexport class MasterChangePolicy {\n @PrimaryGeneratedColumn('uuid') id: string\n @ManyToOne(() => Domain, { nullable: false }) domain: Domain\n @RelationId((row: MasterChangePolicy) => row.domain) domainId: string\n @Column() axis: string\n @Column() approvalRequired: boolean\n @Column('text') reason: string\n /**\n * 이 줄이 물러난 시각 — 비어 있는 줄이 **지금 정책**이다.\n *\n * 차례를 `createdAt` 으로 세우지 않는다. sqlite 의 `datetime('now')` 는 초까지라, 한 사람이 같은\n * 초에 두 번 바꾸면 어느 줄이 나중인지 저장소가 못 가린다. 물러난 줄에 표를 하면 그 물음이 사라진다.\n */\n @Column({ nullable: true }) supersededAt: Date\n /**\n * 누가 정했나 — **비어 있으면 아무도 안 정한 것**이고, 그 줄은 기본값으로 선 줄이다.\n *\n * 사람이 안 정한 줄에 사람을 적으면 그 사람이 정한 것이 된다. 사업장을 만든 사람도 이 축을 보고\n * 고른 적이 없다.\n */\n @ManyToOne(() => User, { nullable: true }) creator: User\n @RelationId((row: MasterChangePolicy) => row.creator) creatorId: string\n @CreateDateColumn() createdAt: Date\n}\n\n/** 아무도 안 정한 축이 도는 방식 — 바꾸려면 여기 하나만 고치면 된다. */\nexport const DEFAULT_APPROVAL_REQUIRED = false\n\n/**\n * 이 축이 지금 어떻게 도는가. **아무도 안 정했으면 기본값으로 한 줄을 세우고 그것을 답한다.**\n *\n * 전에는 거절했다(`MASTER_POLICY_REQUIRED`). 그래서 새 사업장은 축 열여섯이 전부 막힌 채로 시작했고,\n * 기준정보를 만들려던 사람이 「정책을 먼저 정하라」는 말만 받았다 — 어디서 정하는지는 안 적혀 있었다.\n *\n * 값을 그때그때 지어내지 않고 **줄을 세우는** 까닭은, 개정본이 자기가 어느 정책 아래 만들어졌는지를\n * 그 줄로 가리키기 때문이다(ADR-0090). 가리킬 줄이 없으면 그 물음에 나중에 답할 수 없다.\n *\n * 그 줄의 `creator` 는 비어 있다. 아무도 고른 적이 없다는 것이 사실이고, 사업장을 만든 사람을 적으면\n * 그 사람이 정한 것이 된다.\n */\nexport async function masterChangePolicy(manager: EntityManager, domainId: string, axis: string) {\n policyAxis(axis)\n const policy = await standingPolicy(manager, domainId, axis)\n if (policy) {\n return policy\n }\n\n if (!manager.queryRunner?.isTransactionActive)\n throw new Refusal('TRANSACTION_REQUIRED', {}, 'A transaction is required.')\n\n return manager.save(\n MasterChangePolicy,\n manager.create(MasterChangePolicy, {\n domain: { id: domainId },\n axis,\n approvalRequired: DEFAULT_APPROVAL_REQUIRED,\n reason: 'nobody set this axis; it runs on the default'\n })\n )\n}\n\n/** 이 축에서 물러나지 않은 줄 전부 — 보통 하나다. */\nfunction standingRows(manager: EntityManager, domainId: string, axis: string) {\n return manager.findBy(MasterChangePolicy, { domain: { id: domainId }, axis, supersededAt: IsNull() })\n}\n\n/**\n * 지금 서 있는 줄.\n *\n * 둘 이상이 서 있으면 **가장 늦게 만들어진 것**을 답한다. 그 상태는 이 코드가 못 만들지만, 물러남\n * 표를 두기 전에 쌓인 줄들이 그렇게 남아 있다. 다음 선언이 전부 물러나게 하고 하나로 정리한다.\n */\nexport async function standingPolicy(manager: EntityManager, domainId: string, axis: string) {\n const rows = await standingRows(manager, domainId, axis)\n\n return rows.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()).pop() ?? null\n}\n\n/** 이 도메인에서 지금 서 있는 줄 전부 — 축을 열쇠로. */\nexport async function standingPolicies(manager: EntityManager, domainId: string) {\n const rows = await manager.findBy(MasterChangePolicy, { domain: { id: domainId }, supersededAt: IsNull() })\n\n /* 이른 것부터 담아서 같은 축은 늦은 것이 이긴다 — `standingPolicy` 와 같은 답이 되도록. */\n rows.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime())\n\n return new Map(rows.map(one => [one.axis, one]))\n}\n\nexport async function declareMasterChangePolicy(\n manager: EntityManager,\n domainId: string,\n actorId: string,\n axis: string,\n approvalRequired: boolean,\n reason: string\n) {\n if (!manager.queryRunner?.isTransactionActive)\n throw new Refusal('TRANSACTION_REQUIRED', {}, 'A transaction is required.')\n policyAxis(axis)\n const domain = await manager.findOneByOrFail(Domain, { id: domainId })\n if (domain.owner !== actorId)\n throw new Refusal(\n 'MASTER_POLICY_OWNER_REQUIRED',\n {},\n 'Only the domain owner may declare or change the master change policy.'\n )\n if (!reason?.trim()) throw new Refusal('MASTER_POLICY_REASON_REQUIRED', {}, 'Explain the policy declaration.')\n\n /*\n * 규제를 **거는** 쪽만 본다. 푸는 쪽은 결재선이 비어 있어도 되고, 오히려 비어서 멈춘 축을 푸는 것이\n * 이 화면으로 할 수 있는 일이어야 한다.\n */\n if (approvalRequired) {\n /*\n * 개정본 문이 없는 축은 **켜는 것부터 막는다**(2026-09-24). 켜면 직접 쓰기가 전부 거절되는데 결재로\n * 보낼 곳이 없어서 그 축이 통째로 잠긴다. 결재선을 묻기 전에 본다 — 결재선이 있어도 보낼 문이 없다.\n */\n if (!axisHasRevision(axis))\n throw new Refusal(\n 'MASTER_AXIS_HAS_NO_REVISION',\n { axis },\n 'This master cannot be sent for approval yet, so it cannot be set to change only after approval.'\n )\n await assertApprovalRouteReady(manager, domainId, axis)\n }\n\n const standing = await standingRows(manager, domainId, axis)\n\n /*\n * 같은 값을 다시 정하는 것은 아무 일도 아니다 — **하나만 서 있을 때** 그렇다. 여럿이 서 있으면\n * 어느 것이 지금 것인지가 안 정해진 상태이므로, 값이 같아 보여도 전부 물리고 하나로 다시 세운다.\n */\n if (standing.length === 1 && standing[0].approvalRequired === approvalRequired) {\n return standing[0]\n }\n\n const supersededAt = new Date()\n for (const row of standing) {\n row.supersededAt = supersededAt\n await manager.save(MasterChangePolicy, row)\n }\n\n /*\n * 바뀌면 **새 줄을 세운다. 있던 줄은 그대로 둔다.**\n *\n * 지난 개정본들이 그 줄을 가리키고 있다(`RecipeRevision.policy`, RESTRICT). 덮으면 그것들이\n * 소급해서 다른 규칙 아래 만들어진 것이 된다 — 그래서 덮지 않고 새로 세운다. 오늘부터는 새 줄이\n * 현재 정책이고, 지난 것은 자기 때의 줄을 계속 가리킨다.\n */\n return manager.save(\n MasterChangePolicy,\n manager.create(MasterChangePolicy, {\n domain: { id: domainId },\n axis,\n approvalRequired,\n reason,\n creator: { id: actorId }\n })\n )\n}\n\nexport async function assertDirectMasterChange(manager: EntityManager, domainId: string, axis: string) {\n const policy = await standingPolicy(manager, domainId, axis)\n if (policy?.approvalRequired)\n throw new Refusal('MASTER_APPROVAL_REQUIRED', { axis }, 'This master axis requires approval in this domain.')\n}\n\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class MasterChangePolicyResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(() => ScalarObject)\n async masterChangePolicy(@Arg('axis') axis: string, @Ctx() context: ResolverContext) {\n /* 읽기만 하는 자리다. 안 정한 축에 줄을 세우지 않는다 — 그것은 고치러 들어간 쪽이 할 일이다. */\n policyAxis(axis)\n const policy = await standingPolicy(getRepository(MasterChangePolicy).manager, context.state.domain.id, axis)\n // A fresh site's editor must see the same default the first write will use, without inventing a policy id.\n return policy\n ? { ...policy, declared: true }\n : { axis, declared: false, approvalRequired: DEFAULT_APPROVAL_REQUIRED }\n }\n\n /**\n * 축 전부의 정책 상태 — **안 정한 것도 답한다.**\n *\n * 단일 조회처럼 안 정한 축은 기본값과 미선언 상태를 답한다. 목록에는 관리 권한과 결재 경로 상태도 담는다.\n *\n * `canDeclare` 는 **이 사람이 소유자인가**다. 화면이 스스로 판단하지 않게 서버가 말한다 —\n * 눌러 보고 거절당하는 화면이 되지 않도록.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(() => ScalarObject)\n async masterChangePolicies(@Ctx() context: ResolverContext) {\n const { domain, user } = context.state\n const manager = getRepository(MasterChangePolicy).manager\n /*\n * **물러나지 않은 줄만** 읽는다. 축마다 줄이 여럿이라, 전부 담으면 저장소가 주는 차례대로 덮여서\n * 바꾼 뒤에도 화면에 옛 값이 떴다(2026-09-22 화면에서 확인).\n */\n const byAxis = await standingPolicies(manager, domain.id)\n\n return {\n canDeclare: domain.owner === user?.id,\n axes: await Promise.all(\n POLICY_AXES.map(async axis => {\n const policy = byAxis.get(axis)\n /*\n * 결재 길이 준비됐나 — **화면이 누르기 전에 알아야 한다.** 답이 없는 축은 이 앱이 아직 이\n * 물음에 답할 길이 없다는 뜻이라 막지 않는다(`inspectApprovalRoute`).\n */\n const route = await inspectApprovalRoute(manager, domain.id, axis)\n\n return {\n axis,\n declared: !!policy,\n /* 줄은 섰지만 사람이 고른 적은 없다 — 화면이 그것을 다르게 보인다. */\n byDefault: !!policy && !policy.creatorId,\n approvalRequired: policy?.approvalRequired ?? null,\n reason: policy?.reason ?? null,\n declaredAt: policy?.createdAt ?? null,\n /* 승인으로 켤 수 있는 축인가 — 아니면 화면은 누르기 전에 그 까닭을 말한다. */\n revisable: axisHasRevision(axis),\n approvalReady: route ? route.ready : true,\n approvalActivity: route?.activity ?? null\n }\n })\n )\n }\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async declareMasterChangePolicy(\n @Arg('axis') axis: string,\n @Arg('approvalRequired') approvalRequired: boolean,\n @Arg('reason') reason: string,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return declareMasterChangePolicy(tx, domain.id, user.id, axis, approvalRequired, reason)\n }\n}\n"]}
|
|
@@ -4,4 +4,4 @@ import { MaterialQuery } from './material-query';
|
|
|
4
4
|
import { MaterialClassResolver, MaterialDefinitionResolver } from './material-master-resolver';
|
|
5
5
|
import { MaterialDefinitionRevisionResolver } from './material-revision-resolver';
|
|
6
6
|
export declare const entities: (typeof MaterialClass | typeof MaterialDefinition | typeof import("./material-revision").MaterialDefinitionRevision | typeof import("./material-revision").MaterialDefinitionPlan | typeof import("./material-revision").MaterialDefinitionSegment | typeof import("./material-revision").MaterialDefinitionBasis)[];
|
|
7
|
-
export declare const resolvers: (typeof
|
|
7
|
+
export declare const resolvers: (typeof MaterialClassResolver | typeof MaterialDefinitionResolver | typeof MaterialDefinitionRevisionResolver | typeof MaterialQuery)[];
|
|
@@ -52,7 +52,7 @@ export declare class MaterialDefinitionRevisionResolver {
|
|
|
52
52
|
createMaterialDefinitionDraft(content: MaterialDefinitionDraftContent, materialId: string, name: string, baseRevisionId: string, context: ResolverContext): Promise<import("./material-revision").MaterialDefinitionRevision>;
|
|
53
53
|
editMaterialDefinitionDraft(revisionId: string, editGeneration: number, content: MaterialDefinitionDraftContent, context: ResolverContext): Promise<import("./material-revision").MaterialDefinitionRevision>;
|
|
54
54
|
/** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */
|
|
55
|
-
saveAndPublishMaterialDefinition(content: MaterialDefinitionDraftContent, materialId: string, name: string, baseRevisionId: string, context: ResolverContext): Promise<{
|
|
55
|
+
saveAndPublishMaterialDefinition(content: MaterialDefinitionDraftContent, materialId: string, name: string, baseRevisionId: string, revisionId: string, editGeneration: number, context: ResolverContext): Promise<{
|
|
56
56
|
revision: import("./material-revision").MaterialDefinitionRevision;
|
|
57
57
|
plan: import("./material-revision").MaterialDefinitionPlan;
|
|
58
58
|
}>;
|
|
@@ -23,9 +23,9 @@ let MaterialDefinitionRevisionResolver = class MaterialDefinitionRevisionResolve
|
|
|
23
23
|
return (0, material_revision_service_1.editMaterialDefinitionDraft)(tx, domain.id, user.id, revisionId, editGeneration, content);
|
|
24
24
|
}
|
|
25
25
|
/** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */
|
|
26
|
-
async saveAndPublishMaterialDefinition(content, materialId, name, baseRevisionId, context) {
|
|
26
|
+
async saveAndPublishMaterialDefinition(content, materialId, name, baseRevisionId, revisionId, editGeneration, context) {
|
|
27
27
|
const { tx, domain, user } = context.state;
|
|
28
|
-
return (0, material_revision_service_1.saveAndPublishMaterialDefinition)(tx, domain.id, user.id, { materialId, name, baseRevisionId, content });
|
|
28
|
+
return (0, material_revision_service_1.saveAndPublishMaterialDefinition)(tx, domain.id, user.id, { materialId, name, baseRevisionId, content, revisionId, editGeneration });
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
exports.MaterialDefinitionRevisionResolver = MaterialDefinitionRevisionResolver;
|
|
@@ -82,9 +82,11 @@ tslib_1.__decorate([
|
|
|
82
82
|
tslib_1.__param(1, (0, type_graphql_1.Arg)('materialId', () => String, { nullable: true })),
|
|
83
83
|
tslib_1.__param(2, (0, type_graphql_1.Arg)('name', () => String, { nullable: true })),
|
|
84
84
|
tslib_1.__param(3, (0, type_graphql_1.Arg)('baseRevisionId', () => String, { nullable: true })),
|
|
85
|
-
tslib_1.__param(4, (0, type_graphql_1.
|
|
85
|
+
tslib_1.__param(4, (0, type_graphql_1.Arg)('revisionId', () => String, { nullable: true })),
|
|
86
|
+
tslib_1.__param(5, (0, type_graphql_1.Arg)('editGeneration', () => type_graphql_1.Int, { nullable: true })),
|
|
87
|
+
tslib_1.__param(6, (0, type_graphql_1.Ctx)()),
|
|
86
88
|
tslib_1.__metadata("design:type", Function),
|
|
87
|
-
tslib_1.__metadata("design:paramtypes", [Object, String, String, String, Object]),
|
|
89
|
+
tslib_1.__metadata("design:paramtypes", [Object, String, String, String, String, Number, Object]),
|
|
88
90
|
tslib_1.__metadata("design:returntype", Promise)
|
|
89
91
|
], MaterialDefinitionRevisionResolver.prototype, "saveAndPublishMaterialDefinition", null);
|
|
90
92
|
exports.MaterialDefinitionRevisionResolver = MaterialDefinitionRevisionResolver = tslib_1.__decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material-revision-resolver.js","sourceRoot":"","sources":["../../../server/service/material/material-revision-resolver.ts"],"names":[],"mappings":";;;;AAAA,+CAAiG;AACjG,iDAAkF;AAClF,+DAA0D;AAC1D,2EAAoP;AAI7O,IAAM,kCAAkC,GAAxC,MAAM,kCAAkC;IAIvC,AAAN,KAAK,CAAC,8BAA8B,CAAoB,UAAkB,EAAoC,cAAsB,EAAS,OAAwB;QACnK,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,OAAO,IAAA,gEAAoC,EAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,cAAc,CAAC,CAAA;IACjG,CAAC;IAGK,AAAN,KAAK,CAAC,2BAA2B,CAAoB,UAAkB,EAAS,OAAwB;QACtG,OAAO,IAAA,8DAAkC,EAAC,IAAA,qBAAa,EAAC,wCAAkB,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;IAC3H,CAAC;IAKK,AAAN,KAAK,CAAC,6BAA6B,CACG,OAAuC,EACtB,UAAkB,EACxB,IAAY,EACF,cAAsB,EACxE,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,OAAO,IAAA,yDAA6B,EAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,CAAA;IAC7G,CAAC;IAKK,AAAN,KAAK,CAAC,2BAA2B,CACZ,UAAkB,EACH,cAAsB,EACpB,OAAuC,EACpE,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,OAAO,IAAA,uDAA2B,EAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,CAAA;IACjG,CAAC;IAED,gEAAgE;IAI1D,AAAN,KAAK,CAAC,gCAAgC,CACA,OAAuC,EACtB,UAAkB,EACxB,IAAY,EACF,cAAsB,
|
|
1
|
+
{"version":3,"file":"material-revision-resolver.js","sourceRoot":"","sources":["../../../server/service/material/material-revision-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Int, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql'\nimport { getRepository, ScalarObject, SpeakRefusals } from '@things-factory/shell'\nimport { MaterialDefinition } from './material-definition'\nimport { saveAndPublishMaterialDefinition, createMaterialDefinitionDraft, editMaterialDefinitionDraft, publishUnregulatedMaterialDefinition, materialDefinitionRevisionOverview, MaterialDefinitionDraftContent } from './material-revision-service'\n\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class MaterialDefinitionRevisionResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async publishMaterialDefinitionDraft(@Arg('revisionId') revisionId: string, @Arg('editGeneration', () => Int) editGeneration: number, @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return publishUnregulatedMaterialDefinition(tx, domain.id, user.id, revisionId, editGeneration)\n }\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(() => ScalarObject)\n async materialDefinitionRevisions(@Arg('materialId') materialId: string, @Ctx() context: ResolverContext) {\n return materialDefinitionRevisionOverview(getRepository(MaterialDefinition).manager, context.state.domain.id, materialId)\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async createMaterialDefinitionDraft(\n @Arg('content', () => ScalarObject) content: MaterialDefinitionDraftContent,\n @Arg('materialId', () => String, { nullable: true }) materialId: string,\n @Arg('name', () => String, { nullable: true }) name: string,\n @Arg('baseRevisionId', () => String, { nullable: true }) baseRevisionId: string,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return createMaterialDefinitionDraft(tx, domain.id, user.id, { materialId, name, baseRevisionId, content })\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async editMaterialDefinitionDraft(\n @Arg('revisionId') revisionId: string,\n @Arg('editGeneration', () => Int) editGeneration: number,\n @Arg('content', () => ScalarObject) content: MaterialDefinitionDraftContent,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return editMaterialDefinitionDraft(tx, domain.id, user.id, revisionId, editGeneration, content)\n }\n\n /** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async saveAndPublishMaterialDefinition(\n @Arg('content', () => ScalarObject) content: MaterialDefinitionDraftContent,\n @Arg('materialId', () => String, { nullable: true }) materialId: string,\n @Arg('name', () => String, { nullable: true }) name: string,\n @Arg('baseRevisionId', () => String, { nullable: true }) baseRevisionId: string,\n @Arg('revisionId', () => String, { nullable: true }) revisionId: string,\n @Arg('editGeneration', () => Int, { nullable: true }) editGeneration: number,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return saveAndPublishMaterialDefinition(tx, domain.id, user.id, { materialId, name, baseRevisionId, content, revisionId, editGeneration })\n }\n}\n"]}
|
|
@@ -168,6 +168,8 @@ export declare function saveAndPublishMaterialDefinition(manager: EntityManager,
|
|
|
168
168
|
name?: string;
|
|
169
169
|
baseRevisionId?: string;
|
|
170
170
|
content: MaterialDefinitionDraftContent;
|
|
171
|
+
revisionId?: string;
|
|
172
|
+
editGeneration?: number;
|
|
171
173
|
}): Promise<{
|
|
172
174
|
revision: MaterialDefinitionRevision;
|
|
173
175
|
plan: MaterialDefinitionPlan;
|
|
@@ -669,7 +669,12 @@ async function effectiveMaterialDefinition(manager, domainId, material, at = new
|
|
|
669
669
|
* 반쯤 저장된 것이 남지 않는다. 개정본 · 적용계획 · 구간은 두 걸음 때와 똑같이 선다.
|
|
670
670
|
*/
|
|
671
671
|
async function saveAndPublishMaterialDefinition(manager, domainId, actorId, asked) {
|
|
672
|
-
|
|
672
|
+
// Reuse the owned draft and its concurrency guard; publishing failure rolls back the edit too.
|
|
673
|
+
if (asked.revisionId && !Number.isInteger(asked.editGeneration))
|
|
674
|
+
refuse('DRAFT_CONFLICT');
|
|
675
|
+
const draft = asked.revisionId
|
|
676
|
+
? await editMaterialDefinitionDraft(manager, domainId, actorId, asked.revisionId, asked.editGeneration, asked.content)
|
|
677
|
+
: await createMaterialDefinitionDraft(manager, domainId, actorId, asked);
|
|
673
678
|
const plan = await publishUnregulatedMaterialDefinition(manager, domainId, actorId, draft.id, draft.editGeneration);
|
|
674
679
|
return { revision: await revision(manager, domainId, draft.id, false), plan };
|
|
675
680
|
}
|