@things-factory/ops-master 10.1.35 → 10.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/pages/master/applied-when-dialog.d.ts +45 -0
- package/dist-client/pages/master/applied-when-dialog.js +139 -0
- package/dist-client/pages/master/applied-when-dialog.js.map +1 -0
- package/dist-client/pages/master/assignment-fields.d.ts +28 -0
- package/dist-client/pages/master/assignment-fields.js +55 -0
- package/dist-client/pages/master/assignment-fields.js.map +1 -0
- package/dist-client/pages/master/equipment.js +1 -0
- package/dist-client/pages/master/equipment.js.map +1 -1
- package/dist-client/pages/master/master-page-base.d.ts +14 -0
- package/dist-client/pages/master/master-page-base.js +40 -4
- package/dist-client/pages/master/master-page-base.js.map +1 -1
- package/dist-client/pages/master/operational-location.js +1 -0
- package/dist-client/pages/master/operational-location.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/assignment/applied-when.d.ts +24 -0
- package/dist-server/service/assignment/applied-when.js +16 -0
- package/dist-server/service/assignment/applied-when.js.map +1 -0
- package/dist-server/service/assignment/assignment-claim.d.ts +111 -0
- package/dist-server/service/assignment/assignment-claim.js +160 -0
- package/dist-server/service/assignment/assignment-claim.js.map +1 -0
- package/dist-server/service/assignment/assignment-history.d.ts +87 -0
- package/dist-server/service/assignment/assignment-history.js +250 -0
- package/dist-server/service/assignment/assignment-history.js.map +1 -0
- package/dist-server/service/assignment/assignment-write.d.ts +25 -0
- package/dist-server/service/assignment/assignment-write.js +69 -0
- package/dist-server/service/assignment/assignment-write.js.map +1 -0
- package/dist-server/service/equipment/equipment-master-resolver.d.ts +9 -1
- package/dist-server/service/equipment/equipment-master-resolver.js +6 -3
- package/dist-server/service/equipment/equipment-master-resolver.js.map +1 -1
- package/dist-server/service/index.d.ts +3 -0
- package/dist-server/service/index.js +3 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/location/location-master-resolver.d.ts +4 -1
- package/dist-server/service/location/location-master-resolver.js +6 -3
- package/dist-server/service/location/location-master-resolver.js.map +1 -1
- package/dist-server/service/master-crud.d.ts +11 -0
- package/dist-server/service/master-crud.js +12 -1
- package/dist-server/service/master-crud.js.map +1 -1
- package/dist-server/service/material/material-revision-service.js +13 -0
- package/dist-server/service/material/material-revision-service.js.map +1 -1
- package/dist-server/service/recipe/recipe-revision-service.js +13 -0
- package/dist-server/service/recipe/recipe-revision-service.js.map +1 -1
- package/dist-server/service/test-spec/test-spec-revision-service.js +14 -0
- package/dist-server/service/test-spec/test-spec-revision-service.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AppliedWhen } from '../assignment/applied-when';
|
|
1
2
|
import { ListParam } from '@things-factory/shell';
|
|
2
3
|
import { MasterPatch } from '../master-crud';
|
|
3
4
|
import { OperationalLocation } from './operational-location';
|
|
@@ -53,5 +54,7 @@ export declare class OperationalLocationResolver {
|
|
|
53
54
|
* 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는
|
|
54
55
|
* 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.
|
|
55
56
|
*/
|
|
56
|
-
updateMultipleOperationalLocation(patches: MasterPatch[], context: ResolverContext
|
|
57
|
+
updateMultipleOperationalLocation(patches: MasterPatch[], context: ResolverContext,
|
|
58
|
+
/** **언제부터 그러한가** — 근무조 선언과 부모 관계를 고칠 때만 온다(§`applied-when`). */
|
|
59
|
+
applied?: AppliedWhen): Promise<OperationalLocation[]>;
|
|
57
60
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.OperationalLocationResolver = exports.OperationalLocationList = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const applied_when_1 = require("../assignment/applied-when");
|
|
6
7
|
const shell_1 = require("@things-factory/shell");
|
|
7
8
|
const type_graphql_2 = require("type-graphql");
|
|
8
9
|
const shell_2 = require("@things-factory/shell");
|
|
@@ -234,11 +235,12 @@ let OperationalLocationResolver = class OperationalLocationResolver {
|
|
|
234
235
|
* 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는
|
|
235
236
|
* 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.
|
|
236
237
|
*/
|
|
237
|
-
async updateMultipleOperationalLocation(patches, context) {
|
|
238
|
+
async updateMultipleOperationalLocation(patches, context, applied) {
|
|
238
239
|
const { domain, user, tx } = context.state;
|
|
239
240
|
const axis = (0, master_axis_1.masterAxisOf)('operationalLocation');
|
|
240
241
|
const saved = await (0, master_crud_1.saveMasterPatches)(tx, domain, axis.entity, patches, user, {
|
|
241
|
-
hasEffectivePeriod: axis.hasEffectivePeriod
|
|
242
|
+
hasEffectivePeriod: axis.hasEffectivePeriod,
|
|
243
|
+
...(0, applied_when_1.appliedOptions)(applied)
|
|
242
244
|
});
|
|
243
245
|
return saved;
|
|
244
246
|
}
|
|
@@ -299,8 +301,9 @@ tslib_1.__decorate([
|
|
|
299
301
|
(0, type_graphql_2.Mutation)(returns => [operational_location_1.OperationalLocation], { description: 'To create, change or retire operational locations' }),
|
|
300
302
|
tslib_1.__param(0, (0, type_graphql_2.Arg)('patches', type => [shell_2.ScalarObject])),
|
|
301
303
|
tslib_1.__param(1, (0, type_graphql_2.Ctx)()),
|
|
304
|
+
tslib_1.__param(2, (0, type_graphql_2.Arg)('applied', type => shell_2.ScalarObject, { nullable: true })),
|
|
302
305
|
tslib_1.__metadata("design:type", Function),
|
|
303
|
-
tslib_1.__metadata("design:paramtypes", [Array, Object]),
|
|
306
|
+
tslib_1.__metadata("design:paramtypes", [Array, Object, Object]),
|
|
304
307
|
tslib_1.__metadata("design:returntype", Promise)
|
|
305
308
|
], OperationalLocationResolver.prototype, "updateMultipleOperationalLocation", null);
|
|
306
309
|
exports.OperationalLocationResolver = OperationalLocationResolver = tslib_1.__decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"location-master-resolver.js","sourceRoot":"","sources":["../../../server/service/location/location-master-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { UseMiddleware } from 'type-graphql'\nimport { SpeakRefusals } from '@things-factory/shell'\nimport { Args, Arg, Ctx, Directive, FieldResolver, Int, Mutation, ObjectType, Field, Query, Resolver, Root } from 'type-graphql'\n\nimport { Domain, ListParam, ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { OperationalLocation } from './operational-location'\nimport { Person } from '../personnel/person'\nimport { Equipment } from '../equipment/equipment'\nimport { PhysicalAsset } from '../asset/physical-asset'\nimport { cappedList, indexReferrers } from '../resource/referrers'\n\n/**\n * 자리 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of operational locations' })\nexport class OperationalLocationList {\n @Field(type => [OperationalLocation])\n items: OperationalLocation[]\n\n @Field(type => Int)\n total: number\n}\n\n/**\n * 「바로 아래에 몇이 있나」를 세는 곳.\n *\n * ── 물어본 요청만 센다 ──────────────────────────────────────────────────────\n * 처음에는 목록 리졸버가 늘 세게 했다. 그러면 **개수를 쓰지 않는 조회도 값을 치른다** — 고르기 팝업,\n * 자동완성, 다른 화면의 목록까지 전부. 로케이션 목록은 여러 곳에서 부른다.\n *\n * 그래서 `childCount` 를 필드 리졸버로 둔다. GraphQL 이 **물어본 요청에만** 이것을 부르므로, 안 묻는\n * 조회는 질의가 한 번뿐이다. 「이 목록은 개수가 필요하다/아니다」를 서버 쪽에 플래그로 두지 않아도\n * 된다 — 묻는 것이 곧 그 표시다.\n *\n * ── 물었으면 한 번에 센다 ───────────────────────────────────────────────────\n * 필드 리졸버는 줄마다 불린다. 거기서 그때그때 세면 `limit 20` 에 카운트 20회, 100 이면 100회다 —\n * N+1 이다.\n *\n * 그래서 목록 리졸버가 그 페이지를 요청에 남겨 두고(`locationPage`), 첫 줄이 물을 때 **페이지 전체를\n * 한 번에** 세어 요청 안에 담아 둔다. 담는 것은 **결과가 아니라 약속(Promise)** 이다 — 줄들이 거의\n * 동시에 묻기 때문에, 결과를 담으면 스무 개가 각자 질의를 띄운 뒤에야 채워진다.\n *\n * SELECT parent_id, COUNT(1) … WHERE domain = ? AND parent_id IN (…) GROUP BY parent_id\n *\n * `IN` 에 들어가는 것은 그 페이지의 아이디와 이름뿐이라 표 전체 크기와 무관하다.\n * `ix_ops_operational_location_1`(도메인 · 상위)이 이 질의를 받는다.\n *\n * ── 상위를 두 가지로 찾는다 ──────────────────────────────────────────────────\n * `parentId` 는 외래 키가 아니라 문자열이라 쓰는 쪽이 정한다. 지금 데이터는 아이디가 아니라 **이름**을\n * 담고 있다(`LINE-1` 의 상위가 `PLANT-1`). 한쪽만 보면 개수가 오류 보고 없이 0 이 된다.\n */\nasync function countChildren(locations: OperationalLocation[], domain: Domain): Promise<Map<string, number>> {\n const keys = [...new Set(locations.flatMap(location => [location.id, location.name]).filter(Boolean))]\n\n if (!keys.length) return new Map()\n\n const counted = await getRepository(OperationalLocation)\n .createQueryBuilder('location')\n .select('location.parentId', 'parentId')\n .addSelect('COUNT(1)', 'count')\n .where('location.domain = :domain', { domain: domain.id })\n .andWhere('location.parentId IN (:...keys)', { keys })\n .groupBy('location.parentId')\n .getRawMany()\n\n return new Map<string, number>(counted.map(row => [row.parentId, Number(row.count)]))\n}\n\n/**\n * 아이디로 적힌 자식과 이름으로 적힌 자식을 **더한다.**\n *\n * 같은 자식이 두 규약으로 중복 등록돼 있으면 개수가 부풀 수 있다. 그런 데이터는 이미 결함이지만, 여기서\n * 한쪽을 조용히 버리지는 않는다 — 버리면 어느 쪽이 빠졌는지 아무도 모른다.\n */\nfunction sumFor(location: OperationalLocation, counted: Map<string, number>): number {\n return (counted.get(location.id) || 0) + (location.name ? counted.get(location.name) || 0 : 0)\n}\n\n/**\n * **이 자리에 무엇이 있나** — 들어오는 관계.\n *\n * ── 왜 필요한가 ────────────────────────────────────────────────────────────\n * 자리 하나를 열어도 「여기서 누가 일하나 · 무슨 설비가 있나」를 알 수 없었다. 사람 화면을 열어\n * 근무 자리로 걸러야 했고, 설비는 또 설비 화면에서 같은 일을 해야 했다. 다른 화면의 참조 칸을\n * 눌러 자리로 걸어 들어와도 그 자리가 무엇인지는 이름뿐이었다.\n *\n * ── 줄마다 세지 않는다 ─────────────────────────────────────────────────────\n * `childCount` 와 같은 방식이다. 목록 리졸버가 그 페이지를 요청에 남겨 두고, 첫 줄이 물을 때\n * **페이지 전체를 한 번에** 묻는다. 담는 것은 결과가 아니라 **약속**이다 — 줄들이 거의 동시에\n * 물으므로 결과를 담으면 스무 개가 각자 질의를 띄운다.\n *\n * ── 자리를 두 가지로 찾는다 ────────────────────────────────────────────────\n * `homeLocation` 은 외래 키가 아니라 문자열이라 쓰는 쪽이 정한다. 지금 자료는 **이름**을 담는다\n * (`P-ECU-S-0001` 의 근무 자리가 `ECU-SUB-01`). 아이디도 함께 넣어 묻는다 — 한쪽만 보면 목록이\n * 오류 보고 없이 빈다. `childCount` 가 같은 이유로 그렇게 한다.\n */\n\n/** 한 자리에 보일 이름 수. 넘치면 몇이 남았는지 함께 낸다. */\nconst OCCUPANT_SHOWN = 8\n\ninterface OccupantScan {\n staff: Map<string, string[]>\n equipment: Map<string, string[]>\n assets: Map<string, string[]>\n}\n\nasync function scanOccupants(locations: OperationalLocation[], domain: Domain): Promise<OccupantScan> {\n const keys = [...new Set(locations.flatMap(one => [one.id, one.name]).filter(Boolean))] as string[]\n\n if (keys.length === 0) {\n return { staff: new Map(), equipment: new Map(), assets: new Map() }\n }\n\n const of = async (Entity: any) => {\n const rows = await getRepository(Entity)\n .createQueryBuilder('row')\n .select(['row.id', 'row.name', 'row.homeLocation'])\n .where('row.domain_id = :domain', { domain: domain.id })\n .andWhere('row.home_location IN (:...keys)', { keys })\n .getMany()\n\n return indexReferrers((rows as any[]).map(one => ({ points: one.homeLocation, name: one.name })))\n }\n\n const [staff, equipment, assets] = await Promise.all([of(Person), of(Equipment), of(PhysicalAsset)])\n\n return { staff, equipment, assets }\n}\n\n/**\n * 이 줄의 답을 낸다.\n *\n * **페이지에 없으면 그 줄만 따로 묻는다.** 한 요청에 목록 조회가 둘 있으면 뒤엣것이 앞엣것의\n * 페이지를 덮어쓰고, 그때 남는 줄들이 「아무도 없다」로 나온다 — 자리가 비어 있는 것과 못 본 것이\n * 같아 보인다. 들어오는 관계는 **비어 있는 것이 기본**이라 이 거짓말이 특히 안 띈다.\n * 틀린 목록보다 질의 한 번이 낫다. `childCount` 가 같은 이유로 같은 자리를 둔다.\n */\nasync function occupantsOf(location: OperationalLocation, context: ResolverContext): Promise<OccupantScan> {\n const state = context.state as {\n domain: Domain\n locationPage?: OperationalLocation[]\n occupantScan?: Promise<OccupantScan>\n }\n\n const page = state.locationPage\n const inPage = !!page?.some(one => one.id === location.id)\n\n if (!inPage) {\n return scanOccupants([location], state.domain)\n }\n\n /* 요청 안에서 한 번만 훑는다. 약속을 담는다. */\n state.occupantScan = state.occupantScan || scanOccupants(page!, state.domain)\n\n return state.occupantScan\n}\n\n/**\n * 한 자리의 이름들을 낸다 — 아이디로도 이름으로도 걸린 것을 합친다.\n *\n * 자료가 어느 쪽으로 적혔는지 자리마다 다를 수 있어 둘 다 본다. 합칠 때 겹치는 것은 한 번만 센다.\n */\nfunction namesAt(index: Map<string, string[]>, location: OperationalLocation): string[] {\n const found = [...(index.get(location.id) ?? []), ...(index.get(location.name) ?? [])]\n\n return [...new Set(found)].sort()\n}\n\n@Resolver(OperationalLocation)\n@UseMiddleware(SpeakRefusals)\nexport class OperationalLocationResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => OperationalLocationList, { description: 'To fetch operational locations' })\n async operationalLocations(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<OperationalLocationList> {\n const { domain } = context.state\n const { items, total } = await listMaster('operationalLocation', params, domain)\n\n const locations = items as OperationalLocation[]\n\n /*\n * 여기서 개수를 세지 않는다. 이 페이지만 요청에 남겨 둔다 — `childCount` 를 **물어본 요청**이\n * 있으면 그 리졸버가 이것을 보고 한 번에 센다(위 머리말).\n */\n context.state.locationPage = locations\n\n return { items: locations, total }\n }\n\n /**\n * 이 자리 바로 아래에 몇이 있나.\n *\n * 계층을 한 단씩 걷는 화면이 이 값으로 「그 줄에 들어갈 것이 있나」를 말한다. 아이콘만으로는 그것을\n * 말하지 못한다 — 눌러 보기 전에는 안에 무엇이 있는지, 있기는 한지 알 수 없다.\n *\n * 세는 방식과 값은 `countChildren` 머리말에 적었다.\n */\n /**\n * 여기서 일하는 사람들.\n *\n * **넘치면 몇이 남았는지 말한다**(`occupantOverflow`). 조용히 자르면 「셋이 있다」와 「서른이\n * 있는데 셋만 보인다」가 같아 보이고, 그 칸을 보고 사람이 판단을 내린다.\n *\n * 아무도 없으면 빈 목록이다 — 없는 것은 없다고 낸다.\n */\n @FieldResolver(type => [String], { description: 'People whose home location is here' })\n async staff(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).staff, location), OCCUPANT_SHOWN).shown\n }\n\n /** 여기 있는 설비들. */\n @FieldResolver(type => [String], { description: 'Equipment stationed here' })\n async equipmentHere(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).equipment, location), OCCUPANT_SHOWN).shown\n }\n\n /** 여기 있는 자산들 — 공구 · 지그처럼 옮겨 다니는 것. */\n @FieldResolver(type => [String], { description: 'Physical assets kept here' })\n async assetsHere(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).assets, location), OCCUPANT_SHOWN).shown\n }\n\n /**\n * 위 세 칸에서 **안 보인 것이 몇인가.**\n *\n * 셋을 합쳐 하나로 낸다. 칸마다 따로 두면 화면이 숫자 셋을 더 들고 있어야 하는데, 사람이 알고\n * 싶은 것은 「이 자리에 더 있나」 하나다.\n */\n @FieldResolver(type => Int, { description: 'How many occupants are not shown in the lists above' })\n async occupantOverflow(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<number> {\n const scan = await occupantsOf(location, context)\n\n return (\n cappedList(namesAt(scan.staff, location), OCCUPANT_SHOWN).hidden +\n cappedList(namesAt(scan.equipment, location), OCCUPANT_SHOWN).hidden +\n cappedList(namesAt(scan.assets, location), OCCUPANT_SHOWN).hidden\n )\n }\n\n @FieldResolver(type => Int, { description: 'How many locations sit directly under this one' })\n async childCount(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<number> {\n const { domain, locationPage } = context.state as { domain: Domain; locationPage?: OperationalLocation[] }\n\n const page = locationPage as OperationalLocation[] | undefined\n const inPage = !!page?.some(one => one.id === location.id)\n\n /*\n * 목록 조회가 남긴 페이지에 없으면 그 줄만 센다.\n *\n * 한 요청에 목록 조회가 둘 있으면 뒤엣것이 앞엣것의 페이지를 덮어쓴다. 그때 남는 줄들을 조용히 0 으로\n * 두지 않는다 — 틀린 개수보다 질의 한 번이 낫다.\n */\n if (!inPage) {\n const counted = await countChildren([location], domain)\n return sumFor(location, counted)\n }\n\n /*\n * 요청 안에서 한 번만 센다. **약속을 담는다** — 줄들이 거의 동시에 묻기 때문에 결과를 담으면\n * 스무 개가 각자 질의를 띄운다.\n */\n const state = context.state as { locationChildCounts?: Promise<Map<string, number>> }\n state.locationChildCounts = state.locationChildCounts || countChildren(page!, domain)\n\n return sumFor(location, await state.locationChildCounts)\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [OperationalLocation], { description: 'To create, change or retire operational locations' })\n async updateMultipleOperationalLocation(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<OperationalLocation[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('operationalLocation')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as OperationalLocation[]\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"location-master-resolver.js","sourceRoot":"","sources":["../../../server/service/location/location-master-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { UseMiddleware } from 'type-graphql'\nimport { AppliedWhen, appliedOptions } from '../assignment/applied-when'\nimport { SpeakRefusals } from '@things-factory/shell'\nimport { Args, Arg, Ctx, Directive, FieldResolver, Int, Mutation, ObjectType, Field, Query, Resolver, Root } from 'type-graphql'\n\nimport { Domain, ListParam, ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { OperationalLocation } from './operational-location'\nimport { Person } from '../personnel/person'\nimport { Equipment } from '../equipment/equipment'\nimport { PhysicalAsset } from '../asset/physical-asset'\nimport { cappedList, indexReferrers } from '../resource/referrers'\n\n/**\n * 자리 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of operational locations' })\nexport class OperationalLocationList {\n @Field(type => [OperationalLocation])\n items: OperationalLocation[]\n\n @Field(type => Int)\n total: number\n}\n\n/**\n * 「바로 아래에 몇이 있나」를 세는 곳.\n *\n * ── 물어본 요청만 센다 ──────────────────────────────────────────────────────\n * 처음에는 목록 리졸버가 늘 세게 했다. 그러면 **개수를 쓰지 않는 조회도 값을 치른다** — 고르기 팝업,\n * 자동완성, 다른 화면의 목록까지 전부. 로케이션 목록은 여러 곳에서 부른다.\n *\n * 그래서 `childCount` 를 필드 리졸버로 둔다. GraphQL 이 **물어본 요청에만** 이것을 부르므로, 안 묻는\n * 조회는 질의가 한 번뿐이다. 「이 목록은 개수가 필요하다/아니다」를 서버 쪽에 플래그로 두지 않아도\n * 된다 — 묻는 것이 곧 그 표시다.\n *\n * ── 물었으면 한 번에 센다 ───────────────────────────────────────────────────\n * 필드 리졸버는 줄마다 불린다. 거기서 그때그때 세면 `limit 20` 에 카운트 20회, 100 이면 100회다 —\n * N+1 이다.\n *\n * 그래서 목록 리졸버가 그 페이지를 요청에 남겨 두고(`locationPage`), 첫 줄이 물을 때 **페이지 전체를\n * 한 번에** 세어 요청 안에 담아 둔다. 담는 것은 **결과가 아니라 약속(Promise)** 이다 — 줄들이 거의\n * 동시에 묻기 때문에, 결과를 담으면 스무 개가 각자 질의를 띄운 뒤에야 채워진다.\n *\n * SELECT parent_id, COUNT(1) … WHERE domain = ? AND parent_id IN (…) GROUP BY parent_id\n *\n * `IN` 에 들어가는 것은 그 페이지의 아이디와 이름뿐이라 표 전체 크기와 무관하다.\n * `ix_ops_operational_location_1`(도메인 · 상위)이 이 질의를 받는다.\n *\n * ── 상위를 두 가지로 찾는다 ──────────────────────────────────────────────────\n * `parentId` 는 외래 키가 아니라 문자열이라 쓰는 쪽이 정한다. 지금 데이터는 아이디가 아니라 **이름**을\n * 담고 있다(`LINE-1` 의 상위가 `PLANT-1`). 한쪽만 보면 개수가 오류 보고 없이 0 이 된다.\n */\nasync function countChildren(locations: OperationalLocation[], domain: Domain): Promise<Map<string, number>> {\n const keys = [...new Set(locations.flatMap(location => [location.id, location.name]).filter(Boolean))]\n\n if (!keys.length) return new Map()\n\n const counted = await getRepository(OperationalLocation)\n .createQueryBuilder('location')\n .select('location.parentId', 'parentId')\n .addSelect('COUNT(1)', 'count')\n .where('location.domain = :domain', { domain: domain.id })\n .andWhere('location.parentId IN (:...keys)', { keys })\n .groupBy('location.parentId')\n .getRawMany()\n\n return new Map<string, number>(counted.map(row => [row.parentId, Number(row.count)]))\n}\n\n/**\n * 아이디로 적힌 자식과 이름으로 적힌 자식을 **더한다.**\n *\n * 같은 자식이 두 규약으로 중복 등록돼 있으면 개수가 부풀 수 있다. 그런 데이터는 이미 결함이지만, 여기서\n * 한쪽을 조용히 버리지는 않는다 — 버리면 어느 쪽이 빠졌는지 아무도 모른다.\n */\nfunction sumFor(location: OperationalLocation, counted: Map<string, number>): number {\n return (counted.get(location.id) || 0) + (location.name ? counted.get(location.name) || 0 : 0)\n}\n\n/**\n * **이 자리에 무엇이 있나** — 들어오는 관계.\n *\n * ── 왜 필요한가 ────────────────────────────────────────────────────────────\n * 자리 하나를 열어도 「여기서 누가 일하나 · 무슨 설비가 있나」를 알 수 없었다. 사람 화면을 열어\n * 근무 자리로 걸러야 했고, 설비는 또 설비 화면에서 같은 일을 해야 했다. 다른 화면의 참조 칸을\n * 눌러 자리로 걸어 들어와도 그 자리가 무엇인지는 이름뿐이었다.\n *\n * ── 줄마다 세지 않는다 ─────────────────────────────────────────────────────\n * `childCount` 와 같은 방식이다. 목록 리졸버가 그 페이지를 요청에 남겨 두고, 첫 줄이 물을 때\n * **페이지 전체를 한 번에** 묻는다. 담는 것은 결과가 아니라 **약속**이다 — 줄들이 거의 동시에\n * 물으므로 결과를 담으면 스무 개가 각자 질의를 띄운다.\n *\n * ── 자리를 두 가지로 찾는다 ────────────────────────────────────────────────\n * `homeLocation` 은 외래 키가 아니라 문자열이라 쓰는 쪽이 정한다. 지금 자료는 **이름**을 담는다\n * (`P-ECU-S-0001` 의 근무 자리가 `ECU-SUB-01`). 아이디도 함께 넣어 묻는다 — 한쪽만 보면 목록이\n * 오류 보고 없이 빈다. `childCount` 가 같은 이유로 그렇게 한다.\n */\n\n/** 한 자리에 보일 이름 수. 넘치면 몇이 남았는지 함께 낸다. */\nconst OCCUPANT_SHOWN = 8\n\ninterface OccupantScan {\n staff: Map<string, string[]>\n equipment: Map<string, string[]>\n assets: Map<string, string[]>\n}\n\nasync function scanOccupants(locations: OperationalLocation[], domain: Domain): Promise<OccupantScan> {\n const keys = [...new Set(locations.flatMap(one => [one.id, one.name]).filter(Boolean))] as string[]\n\n if (keys.length === 0) {\n return { staff: new Map(), equipment: new Map(), assets: new Map() }\n }\n\n const of = async (Entity: any) => {\n const rows = await getRepository(Entity)\n .createQueryBuilder('row')\n .select(['row.id', 'row.name', 'row.homeLocation'])\n .where('row.domain_id = :domain', { domain: domain.id })\n .andWhere('row.home_location IN (:...keys)', { keys })\n .getMany()\n\n return indexReferrers((rows as any[]).map(one => ({ points: one.homeLocation, name: one.name })))\n }\n\n const [staff, equipment, assets] = await Promise.all([of(Person), of(Equipment), of(PhysicalAsset)])\n\n return { staff, equipment, assets }\n}\n\n/**\n * 이 줄의 답을 낸다.\n *\n * **페이지에 없으면 그 줄만 따로 묻는다.** 한 요청에 목록 조회가 둘 있으면 뒤엣것이 앞엣것의\n * 페이지를 덮어쓰고, 그때 남는 줄들이 「아무도 없다」로 나온다 — 자리가 비어 있는 것과 못 본 것이\n * 같아 보인다. 들어오는 관계는 **비어 있는 것이 기본**이라 이 거짓말이 특히 안 띈다.\n * 틀린 목록보다 질의 한 번이 낫다. `childCount` 가 같은 이유로 같은 자리를 둔다.\n */\nasync function occupantsOf(location: OperationalLocation, context: ResolverContext): Promise<OccupantScan> {\n const state = context.state as {\n domain: Domain\n locationPage?: OperationalLocation[]\n occupantScan?: Promise<OccupantScan>\n }\n\n const page = state.locationPage\n const inPage = !!page?.some(one => one.id === location.id)\n\n if (!inPage) {\n return scanOccupants([location], state.domain)\n }\n\n /* 요청 안에서 한 번만 훑는다. 약속을 담는다. */\n state.occupantScan = state.occupantScan || scanOccupants(page!, state.domain)\n\n return state.occupantScan\n}\n\n/**\n * 한 자리의 이름들을 낸다 — 아이디로도 이름으로도 걸린 것을 합친다.\n *\n * 자료가 어느 쪽으로 적혔는지 자리마다 다를 수 있어 둘 다 본다. 합칠 때 겹치는 것은 한 번만 센다.\n */\nfunction namesAt(index: Map<string, string[]>, location: OperationalLocation): string[] {\n const found = [...(index.get(location.id) ?? []), ...(index.get(location.name) ?? [])]\n\n return [...new Set(found)].sort()\n}\n\n@Resolver(OperationalLocation)\n@UseMiddleware(SpeakRefusals)\nexport class OperationalLocationResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => OperationalLocationList, { description: 'To fetch operational locations' })\n async operationalLocations(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<OperationalLocationList> {\n const { domain } = context.state\n const { items, total } = await listMaster('operationalLocation', params, domain)\n\n const locations = items as OperationalLocation[]\n\n /*\n * 여기서 개수를 세지 않는다. 이 페이지만 요청에 남겨 둔다 — `childCount` 를 **물어본 요청**이\n * 있으면 그 리졸버가 이것을 보고 한 번에 센다(위 머리말).\n */\n context.state.locationPage = locations\n\n return { items: locations, total }\n }\n\n /**\n * 이 자리 바로 아래에 몇이 있나.\n *\n * 계층을 한 단씩 걷는 화면이 이 값으로 「그 줄에 들어갈 것이 있나」를 말한다. 아이콘만으로는 그것을\n * 말하지 못한다 — 눌러 보기 전에는 안에 무엇이 있는지, 있기는 한지 알 수 없다.\n *\n * 세는 방식과 값은 `countChildren` 머리말에 적었다.\n */\n /**\n * 여기서 일하는 사람들.\n *\n * **넘치면 몇이 남았는지 말한다**(`occupantOverflow`). 조용히 자르면 「셋이 있다」와 「서른이\n * 있는데 셋만 보인다」가 같아 보이고, 그 칸을 보고 사람이 판단을 내린다.\n *\n * 아무도 없으면 빈 목록이다 — 없는 것은 없다고 낸다.\n */\n @FieldResolver(type => [String], { description: 'People whose home location is here' })\n async staff(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).staff, location), OCCUPANT_SHOWN).shown\n }\n\n /** 여기 있는 설비들. */\n @FieldResolver(type => [String], { description: 'Equipment stationed here' })\n async equipmentHere(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).equipment, location), OCCUPANT_SHOWN).shown\n }\n\n /** 여기 있는 자산들 — 공구 · 지그처럼 옮겨 다니는 것. */\n @FieldResolver(type => [String], { description: 'Physical assets kept here' })\n async assetsHere(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<string[]> {\n return cappedList(namesAt((await occupantsOf(location, context)).assets, location), OCCUPANT_SHOWN).shown\n }\n\n /**\n * 위 세 칸에서 **안 보인 것이 몇인가.**\n *\n * 셋을 합쳐 하나로 낸다. 칸마다 따로 두면 화면이 숫자 셋을 더 들고 있어야 하는데, 사람이 알고\n * 싶은 것은 「이 자리에 더 있나」 하나다.\n */\n @FieldResolver(type => Int, { description: 'How many occupants are not shown in the lists above' })\n async occupantOverflow(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<number> {\n const scan = await occupantsOf(location, context)\n\n return (\n cappedList(namesAt(scan.staff, location), OCCUPANT_SHOWN).hidden +\n cappedList(namesAt(scan.equipment, location), OCCUPANT_SHOWN).hidden +\n cappedList(namesAt(scan.assets, location), OCCUPANT_SHOWN).hidden\n )\n }\n\n @FieldResolver(type => Int, { description: 'How many locations sit directly under this one' })\n async childCount(@Root() location: OperationalLocation, @Ctx() context: ResolverContext): Promise<number> {\n const { domain, locationPage } = context.state as { domain: Domain; locationPage?: OperationalLocation[] }\n\n const page = locationPage as OperationalLocation[] | undefined\n const inPage = !!page?.some(one => one.id === location.id)\n\n /*\n * 목록 조회가 남긴 페이지에 없으면 그 줄만 센다.\n *\n * 한 요청에 목록 조회가 둘 있으면 뒤엣것이 앞엣것의 페이지를 덮어쓴다. 그때 남는 줄들을 조용히 0 으로\n * 두지 않는다 — 틀린 개수보다 질의 한 번이 낫다.\n */\n if (!inPage) {\n const counted = await countChildren([location], domain)\n return sumFor(location, counted)\n }\n\n /*\n * 요청 안에서 한 번만 센다. **약속을 담는다** — 줄들이 거의 동시에 묻기 때문에 결과를 담으면\n * 스무 개가 각자 질의를 띄운다.\n */\n const state = context.state as { locationChildCounts?: Promise<Map<string, number>> }\n state.locationChildCounts = state.locationChildCounts || countChildren(page!, domain)\n\n return sumFor(location, await state.locationChildCounts)\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [OperationalLocation], { description: 'To create, change or retire operational locations' })\n async updateMultipleOperationalLocation(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext,\n /** **언제부터 그러한가** — 근무조 선언과 부모 관계를 고칠 때만 온다(§`applied-when`). */\n @Arg('applied', type => ScalarObject, { nullable: true }) applied?: AppliedWhen\n ): Promise<OperationalLocation[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('operationalLocation')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod,\n ...appliedOptions(applied)\n })\n\n return saved as OperationalLocation[]\n }\n}\n"]}
|
|
@@ -28,6 +28,17 @@ type EntityClass = {
|
|
|
28
28
|
new (): ObjectLiteral;
|
|
29
29
|
};
|
|
30
30
|
export interface SaveMasterOptions {
|
|
31
|
+
/**
|
|
32
|
+
* **언제부터 그러한가** — 배정과 선언을 고칠 때.
|
|
33
|
+
*
|
|
34
|
+
* 안 주면 지금부터다. 미래면 주장만 남고 본행은 그 시각이 올 때까지 그대로다
|
|
35
|
+
* (§`claimAssignmentChanges`).
|
|
36
|
+
*/
|
|
37
|
+
appliedAt?: Date;
|
|
38
|
+
/** 과거 시각일 때, **지연 기록인가 이미 적은 것의 정정인가.** 안 주면 지연 기록으로 본다. */
|
|
39
|
+
appliedKind?: 'change' | 'correction';
|
|
40
|
+
/** 정정이면 어느 구간까지인가. */
|
|
41
|
+
appliedUntil?: Date;
|
|
31
42
|
/**
|
|
32
43
|
* 유효 기간을 갖는 축인가.
|
|
33
44
|
*
|
|
@@ -5,6 +5,7 @@ const typeorm_1 = require("typeorm");
|
|
|
5
5
|
const shell_1 = require("@things-factory/shell");
|
|
6
6
|
const master_axis_1 = require("./master-axis");
|
|
7
7
|
const master_change_policy_1 = require("./master-change-policy");
|
|
8
|
+
const assignment_write_1 = require("./assignment/assignment-write");
|
|
8
9
|
/**
|
|
9
10
|
* 그리드가 보낸 변경을 한 번에 적용한다.
|
|
10
11
|
*
|
|
@@ -40,7 +41,17 @@ async function saveMasterPatches(manager, domain, entity, patches, user, options
|
|
|
40
41
|
if (!found) {
|
|
41
42
|
throw new Error(`saveMasterPatches: no such row to change — ${String(id)}`);
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
+
/*
|
|
45
|
+
* ── 배정과 선언은 **주장으로 남기고, 미래는 본행에 안 쓴다** ──────────────
|
|
46
|
+
*
|
|
47
|
+
* 세 칸(`equipment.homeLocation` · `operationalLocation.workShiftNames` · `parentId`)은 가동률
|
|
48
|
+
* 분모를 정한다. 그래서 「언제부터 그러한가」를 함께 받아 이력에 남긴다.
|
|
49
|
+
*
|
|
50
|
+
* **적용 시각이 미래면 본행을 안 건드린다.** 다음 달 이동을 지금 적었다고 다른 제품이 오늘부터
|
|
51
|
+
* 새 자리를 읽으면 안 된다 — 도래하면 `projectDueClaims` 가 옮긴다.
|
|
52
|
+
*/
|
|
53
|
+
const scheduled = await (0, assignment_write_1.claimAssignmentChanges)(manager, domain, axis.key, found, values, user, options);
|
|
54
|
+
results.push(await repository.save({ ...found, ...values, ...scheduled.keepOnRow, updater: user }));
|
|
44
55
|
}
|
|
45
56
|
if (removed.length) {
|
|
46
57
|
await retire(repository, domain, removed, user, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-crud.js","sourceRoot":"","sources":["../../server/service/master-crud.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"master-crud.js","sourceRoot":"","sources":["../../server/service/master-crud.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In, ObjectLiteral, Repository } from 'typeorm'\n\nimport { Domain, Refusal } from '@things-factory/shell'\nimport { MASTER_AXES } from './master-axis'\nimport { assertDirectMasterChange } from './master-change-policy'\nimport { claimAssignmentChanges } from './assignment/assignment-write'\n\n/**\n * 마스터를 채우고 고치는 **한 벌의 규칙** — 열두 축이 같은 함수를 쓴다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 화면(실적 · 검사 · 처분)은 조회 전용이다. 그것은 **일어난 일의 기록**이라, 고칠 수 있으면\n * 「그때 무엇이 있었나」가 「지금 무엇으로 적혀 있나」로 바뀐다.\n *\n * 마스터는 다르다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 **선언**이다. 선언은 바뀌고,\n * 바뀐 것이 지금의 선언이다. 그래서 그리드에서 고친다.\n *\n * ── 지우는 것만 다르게 다룬다 ──────────────────────────────────────────────\n * 유효 기간을 가진 축은 **행을 지우지 않는다.** 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다\n * (어제 실적이 가리키던 설비가 사라지면 그 실적은 어느 설비의 것도 아니게 된다). 대신\n * `effectiveEnd` 를 채워 오늘부터 유효하지 않게 한다.\n *\n * 유효 기간이 없는 축만 실제로 지운다.\n */\n\n/** 그리드가 보내는 표식. `+` 새로 만든 행 · `M` 고친 행 · `-` 지운 행. */\nexport type CuFlag = '+' | 'M' | '-'\n\nexport interface MasterPatch {\n id?: string\n cuFlag?: string\n [key: string]: unknown\n}\n\ntype EntityClass = { new (): ObjectLiteral }\n\nexport interface SaveMasterOptions {\n /**\n * **언제부터 그러한가** — 배정과 선언을 고칠 때.\n *\n * 안 주면 지금부터다. 미래면 주장만 남고 본행은 그 시각이 올 때까지 그대로다\n * (§`claimAssignmentChanges`).\n */\n appliedAt?: Date\n /** 과거 시각일 때, **지연 기록인가 이미 적은 것의 정정인가.** 안 주면 지연 기록으로 본다. */\n appliedKind?: 'change' | 'correction'\n /** 정정이면 어느 구간까지인가. */\n appliedUntil?: Date\n /**\n * 유효 기간을 갖는 축인가.\n *\n * 참이면 지우기가 **`effectiveEnd` 를 채우는 것**이 된다. 거짓이면 행을 지운다.\n */\n hasEffectivePeriod?: boolean\n}\n\n/**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 한 트랜잭션에서 처리한다 — 절반만 반영되면 그리드가 보여 주는 것과 저장된 것이 갈린다.\n */\nexport async function saveMasterPatches(\n manager: EntityManager,\n domain: Domain,\n entity: EntityClass,\n patches: readonly MasterPatch[],\n user: unknown,\n options: SaveMasterOptions = {}\n): Promise<ObjectLiteral[]> {\n const axis = MASTER_AXES.find(axis => axis.entity === entity)\n if (!axis) throw new Error('saveMasterPatches: the entity must be a declared master axis')\n await assertDirectMasterChange(manager, domain.id, axis.key)\n if (['recipeDefinition', 'materialDefinition'].includes(axis.key))\n throw new Refusal('REVISION_REQUIRED', { axis: axis.key }, 'Change this master through a revision draft, including non-regulated publication.')\n const repository = manager.getRepository(entity)\n const results: ObjectLiteral[] = []\n\n const created = patches.filter(patch => flagOf(patch) === '+')\n const updated = patches.filter(patch => flagOf(patch) === 'M')\n const removed = patches.filter(patch => flagOf(patch) === '-')\n\n for (const patch of created) {\n /* 새 행의 `id` 는 그리드가 임시로 붙인 것이다 — 그대로 저장하면 그것이 진짜 키가 된다. */\n const { cuFlag, id, ...values } = patch\n\n results.push(await repository.save({ ...values, domain, creator: user, updater: user }))\n }\n\n for (const patch of updated) {\n const { cuFlag, id, ...values } = patch\n\n if (!id) {\n throw new Error('saveMasterPatches: a changed row must carry its id')\n }\n\n const found = await repository.findOne({ where: { domain: { id: domain.id }, id } })\n\n /*\n * 없는 행을 고치라고 하면 만들지 않는다. 다른 사람이 지웠거나 다른 도메인의 행이고, 둘 다\n * 조용히 새 행을 만들 일이 아니다.\n */\n if (!found) {\n throw new Error(`saveMasterPatches: no such row to change — ${String(id)}`)\n }\n\n /*\n * ── 배정과 선언은 **주장으로 남기고, 미래는 본행에 안 쓴다** ──────────────\n *\n * 세 칸(`equipment.homeLocation` · `operationalLocation.workShiftNames` · `parentId`)은 가동률\n * 분모를 정한다. 그래서 「언제부터 그러한가」를 함께 받아 이력에 남긴다.\n *\n * **적용 시각이 미래면 본행을 안 건드린다.** 다음 달 이동을 지금 적었다고 다른 제품이 오늘부터\n * 새 자리를 읽으면 안 된다 — 도래하면 `projectDueClaims` 가 옮긴다.\n */\n const scheduled = await claimAssignmentChanges(manager, domain, axis.key, found, values, user, options)\n\n results.push(await repository.save({ ...found, ...values, ...scheduled.keepOnRow, updater: user }))\n }\n\n if (removed.length) {\n await retire(repository, domain, removed, user, options)\n }\n\n return results\n}\n\n/**\n * 없앤다 — 유효 기간이 있으면 **끝을 채우고**, 없으면 지운다.\n */\nasync function retire(\n repository: Repository<ObjectLiteral>,\n domain: Domain,\n removed: readonly MasterPatch[],\n user: unknown,\n options: SaveMasterOptions\n): Promise<void> {\n const ids = removed.map(patch => patch.id).filter(Boolean) as string[]\n\n if (!ids.length) {\n return\n }\n\n if (!options.hasEffectivePeriod) {\n await repository.delete({ domain: { id: domain.id }, id: In(ids) })\n return\n }\n\n const rows = await repository.find({ where: { domain: { id: domain.id }, id: In(ids) } })\n const now = new Date()\n\n for (const row of rows) {\n /*\n * 이미 끝이 적혀 있으면 그대로 둔다. 다시 오늘로 바꾸면 「언제부터 안 썼나」가 바뀐다.\n */\n if (row.effectiveEnd) {\n continue\n }\n\n await repository.save({ ...row, effectiveEnd: now, updater: user })\n }\n}\n\nfunction flagOf(patch: MasterPatch): CuFlag {\n const flag = String(patch.cuFlag ?? '').toUpperCase()\n\n if (flag === '+' || flag === 'M' || flag === '-') {\n return flag\n }\n\n /* 표식이 없으면 고침으로 본다 — 그리드가 표식을 안 붙이는 경우가 있고, 만드는 쪽으로 두면 행이 늘어난다. */\n return 'M'\n}\n"]}
|
|
@@ -168,6 +168,18 @@ async function subject(manager, domainId, materialId) {
|
|
|
168
168
|
});
|
|
169
169
|
if (!material)
|
|
170
170
|
refuse('MATERIAL_NOT_FOUND');
|
|
171
|
+
// Compare the current head and latest persisted plan in one SQL snapshot. A historical
|
|
172
|
+
// knownAt query must not compare its selected old plan with the current head.
|
|
173
|
+
const head = await manager.createQueryBuilder(material_definition_1.MaterialDefinition, 'head')
|
|
174
|
+
.leftJoin(material_revision_1.MaterialDefinitionPlan, 'plan', 'plan.material = head.id AND plan.domain = head.domain')
|
|
175
|
+
.select('head.planGeneration', 'generation')
|
|
176
|
+
.addSelect('MAX(plan.generation)', 'latest')
|
|
177
|
+
.where({ id: materialId, domain: { id: domainId } })
|
|
178
|
+
.groupBy('head.id').addGroupBy('head.planGeneration')
|
|
179
|
+
.getRawOne();
|
|
180
|
+
if (!head || Number(head.generation) !== Number(head.latest ?? 0)) {
|
|
181
|
+
throw new shell_1.Refusal('PLAN_INTEGRITY_FAILURE', {}, 'The current plan generation does not match the latest published plan. Contact an administrator.');
|
|
182
|
+
}
|
|
171
183
|
return material;
|
|
172
184
|
}
|
|
173
185
|
async function revision(manager, domainId, revisionId, locked = true) {
|
|
@@ -433,6 +445,7 @@ async function resolveMaterialDefinition(manager, domainId, materialId, business
|
|
|
433
445
|
});
|
|
434
446
|
if (!plan)
|
|
435
447
|
refuse('NO_EFFECTIVE_REVISION');
|
|
448
|
+
await subject(manager, domainId, materialId);
|
|
436
449
|
const query = manager
|
|
437
450
|
.createQueryBuilder(material_revision_1.MaterialDefinitionSegment, 'segment')
|
|
438
451
|
.where({ domain: { id: domainId }, material: { id: materialId }, plan: { id: plan.id } })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material-revision-service.js","sourceRoot":"","sources":["../../../server/service/material/material-revision-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto'\nimport { EntityManager, LessThanOrEqual, MoreThanOrEqual } from 'typeorm'\nimport { Refusal } from '@things-factory/shell'\nimport { masterChangePolicy } from '../master-change-policy'\nimport { materialDraftContent, validateMaterialReferences } from './material-revision-content'\nimport { MaterialDefinition } from './material-definition'\nimport {\n MaterialDefinitionBasis,\n MaterialDefinitionPlan,\n MaterialDefinitionRevision,\n MaterialDefinitionSegment\n} from './material-revision'\n\nexport class MaterialDefinitionRefusal extends Refusal {\n constructor(code: string, detail?: string) {\n super(\n code,\n {},\n detail ?? MATERIAL_DEFINITION_REFUSALS[code] ?? 'The material definition change could not be applied.'\n )\n }\n}\nconst MATERIAL_DEFINITION_REFUSALS: Record<string, string> = {\n TRANSACTION_REQUIRED: 'This change requires a transaction.',\n INVALID_INSTANT: 'Enter a valid date and time including its time zone.',\n INVALID_CONTENT: 'The proposed material content is invalid.',\n MATERIAL_NOT_FOUND: 'The material does not exist in this domain.',\n REVISION_NOT_FOUND: 'The revision does not exist in this domain.',\n INVALID_BASE_REVISION: 'The proposed change is based on a different revision.',\n DRAFT_NOT_OWNED: 'Only the draft author can edit or submit it.',\n REVISION_FROZEN: 'This submitted revision cannot be edited. Create another draft.',\n DRAFT_CONFLICT: 'The draft changed. Reload it before saving.',\n PLAN_CONFLICT: 'The approved schedule changed. Review and submit a new draft.',\n INVALID_SUBMISSION: 'The submitted content does not match the frozen revision.',\n AUTHOR_CANNOT_APPROVE: 'The author cannot approve their own change.',\n RETROACTIVE_IMPACT: 'This change would alter material definitions already used by recorded transactions.',\n FUTURE_PLAN_CONFLICT: 'This change conflicts with an approved future schedule.',\n NO_EFFECTIVE_REVISION: 'There is no published revision effective at the business time.',\n AMBIGUOUS_EFFECTIVITY: 'More than one revision is effective at the business time.',\n REVISION_INTEGRITY_FAILURE: 'The stored revision does not match its signed content.',\n BASIS_CONFLICT: 'This transaction already has a different material or business time.',\n APPROVAL_LINE_REQUIRED: 'Configure an approval line before submitting this change.',\n REVISION_REQUIRED: 'Change the material through a revision draft.'\n}\nfunction refuse(code: string, detail?: string): never {\n throw new MaterialDefinitionRefusal(code, detail)\n}\nfunction transaction(manager: EntityManager) {\n if (!manager.queryRunner?.isTransactionActive) refuse('TRANSACTION_REQUIRED')\n}\n/** Current reads are required after waiting for the subject lock, including MySQL REPEATABLE READ. */\nfunction currentLock(manager: EntityManager) {\n const driver = manager.connection.options.type\n return manager.queryRunner?.isTransactionActive && !['sqlite', 'better-sqlite3', 'sqljs'].includes(driver)\n ? { lock: { mode: 'pessimistic_write' as const } }\n : {}\n}\nfunction instant(value: Date | string): Date {\n if (!(value instanceof Date) && (typeof value !== 'string' || !/(Z|[+-]\\d{2}:\\d{2})$/.test(value)))\n refuse('INVALID_INSTANT')\n const result = new Date(value)\n if (!Number.isFinite(result.getTime())) refuse('INVALID_INSTANT')\n return result\n}\nfunction text(value: unknown, field: string): string {\n if (typeof value !== 'string' || !value.trim()) refuse('INVALID_CONTENT', field)\n return value.trim()\n}\n/** Sorted object keys, ordered arrays, ISO instants. This is the v1 submission encoding. */\nfunction canonical(value: any): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value)\n if (Array.isArray(value)) return '[' + value.map(canonical).join(',') + ']'\n return (\n '{' +\n Object.keys(value)\n .sort()\n .map(key => JSON.stringify(key) + ':' + canonical(value[key]))\n .join(',') +\n '}'\n )\n}\nexport function materialDefinitionSubmissionHash(revision: MaterialDefinitionRevision): string {\n return createHash('sha256')\n .update(\n canonical({\n schemaVersion: 1,\n revisionNumber: revision.revisionNumber,\n policyId: revision.policyId,\n domainId: revision.domainId,\n materialId: revision.materialId,\n baseRevisionId: revision.baseRevisionId,\n baseGeneration: revision.baseGeneration,\n description: revision.description,\n materialClassIds: revision.materialClassIds,\n properties: revision.properties,\n testSpecificationIds: revision.testSpecificationIds,\n effectiveFrom: revision.effectiveFrom.toISOString(),\n reason: revision.reason\n })\n )\n .digest('hex')\n}\n\n/** Display values are a checked projection of the frozen revision, never a second editable source. */\nexport async function materialDefinitionApprovalInput(manager: EntityManager, domainId: string, revisionId: string) {\n const draft = await revision(manager, domainId, revisionId)\n if (!draft.frozenAt || draft.contentHash !== materialDefinitionSubmissionHash(draft)) refuse('INVALID_SUBMISSION')\n const material = await subject(manager, domainId, draft.materialId)\n const base = draft.baseRevisionId ? await revision(manager, domainId, draft.baseRevisionId) : null\n const plan = base ? await manager.findOneBy(MaterialDefinitionPlan, {\n domain: { id: domainId }, material: { id: draft.materialId }, generation: draft.baseGeneration\n }) : null\n const segment = plan && base ? await manager.findOneBy(MaterialDefinitionSegment, {\n domain: { id: domainId }, plan: { id: plan.id }, revision: { id: base.id }\n }) : null\n const values = (row: MaterialDefinitionRevision) => ({\n revisionNumber: row.revisionNumber,\n detail: {\n revisionId: row.id, createdAt: row.createdAt.toISOString(), frozenAt: row.frozenAt?.toISOString(),\n effectiveFrom: row.effectiveFrom.toISOString(), reason: row.reason,\n ...(row.id === base?.id && segment ? { validFrom: segment.validFrom.toISOString(), validTo: segment.validTo?.toISOString() ?? null } : {})\n },\n description: row.description,\n materialClassIds: row.materialClassIds,\n properties: row.properties,\n testSpecificationIds: row.testSpecificationIds\n })\n return {\n headline: material.name,\n reason: draft.reason,\n effectiveFrom: draft.effectiveFrom.toISOString(),\n before: base ? values(base) : null,\n after: values(draft),\n revision: {\n revisionId: draft.id,\n hash: draft.contentHash,\n materialId: draft.materialId,\n baseGeneration: draft.baseGeneration\n }\n }\n}\n\nexport async function assertMaterialDefinitionApprovalInput(\n manager: EntityManager,\n domainId: string,\n input: Record<string, unknown>\n) {\n const reference = input?.revision as { revisionId?: string }\n if (typeof reference?.revisionId !== 'string') refuse('INVALID_SUBMISSION')\n const expected = await materialDefinitionApprovalInput(manager, domainId, reference.revisionId)\n for (const key of Object.keys(expected)) {\n if (canonical(input[key]) !== canonical(expected[key])) refuse('INVALID_SUBMISSION')\n }\n}\n\nexport interface MaterialDefinitionDraftContent {\n description?: string\n materialClassIds?: string[]\n properties?: Record<string, unknown>[]\n testSpecificationIds?: string[]\n effectiveFrom: Date | string\n reason: string\n}\nfunction content(input: MaterialDefinitionDraftContent) {\n return { ...materialDraftContent(input), effectiveFrom: instant(input.effectiveFrom), reason: text(input.reason, 'reason') }\n}\nasync function subject(manager: EntityManager, domainId: string, materialId: string) {\n const material = await manager.findOne(MaterialDefinition, {\n where: { id: materialId, domain: { id: domainId } },\n ...currentLock(manager)\n })\n if (!material) refuse('MATERIAL_NOT_FOUND')\n return material\n}\nasync function revision(manager: EntityManager, domainId: string, revisionId: string, locked = true) {\n const found = await manager.findOne(MaterialDefinitionRevision, {\n where: { id: revisionId, domain: { id: domainId } },\n ...(locked ? currentLock(manager) : {})\n })\n if (!found) refuse('REVISION_NOT_FOUND')\n return found\n}\n/** A write lock valid on every supported SQL backend, including SQLite (no SELECT FOR UPDATE). */\nasync function lockSubject(manager: EntityManager, domainId: string, materialId: string) {\n transaction(manager)\n const locked = await manager\n .createQueryBuilder()\n .update(MaterialDefinition)\n .set({ revisionLock: () => 'revision_lock + 1' })\n .where({ id: materialId, domain: { id: domainId } })\n .execute()\n if (locked.affected !== 1) refuse('MATERIAL_NOT_FOUND')\n return subject(manager, domainId, materialId)\n}\n\nexport async function createMaterialDefinitionDraft(\n manager: EntityManager,\n domainId: string,\n creatorId: string,\n asked: { materialId?: string; name?: string; baseRevisionId?: string; content: MaterialDefinitionDraftContent }\n) {\n transaction(manager)\n const accepted = content(asked.content)\n await validateMaterialReferences(manager, domainId, accepted)\n const policy = await masterChangePolicy(manager, domainId, 'materialDefinition')\n let material: MaterialDefinition\n if (asked.materialId) {\n material = await lockSubject(manager, domainId, asked.materialId)\n } else {\n material = await manager.save(\n MaterialDefinition,\n manager.create(MaterialDefinition, {\n domain: { id: domainId },\n name: text(asked.name, 'name'),\n planGeneration: 0,\n revisionLock: 0,\n creator: { id: creatorId },\n updater: { id: creatorId }\n })\n )\n }\n const previous = await manager.findOne(MaterialDefinitionRevision, {\n where: { domain: { id: domainId }, material: { id: material.id } }, order: { revisionNumber: 'DESC' },\n ...currentLock(manager)\n })\n const revisionNumber = (previous?.revisionNumber ?? 0) + 1\n let baseRevisionId: string | null = null\n if (material.planGeneration > 0) {\n baseRevisionId = (await resolveMaterialDefinition(manager, domainId, material.id, accepted.effectiveFrom)).revision.id\n }\n if (asked.baseRevisionId && asked.baseRevisionId !== baseRevisionId) refuse('INVALID_BASE_REVISION')\n const saved = await manager.save(\n MaterialDefinitionRevision,\n manager.create(MaterialDefinitionRevision, {\n ...accepted,\n policy: { id: policy.id },\n domain: { id: domainId },\n material: { id: material.id },\n baseRevision: baseRevisionId ? { id: baseRevisionId } : null,\n baseGeneration: material.planGeneration,\n revisionNumber,\n editGeneration: 0,\n creator: { id: creatorId },\n createdAt: new Date(),\n frozenAt: null,\n contentHash: null,\n activityInstanceId: null\n })\n )\n return revision(manager, domainId, saved.id)\n}\n\nexport async function editMaterialDefinitionDraft(\n manager: EntityManager,\n domainId: string,\n actorId: string,\n revisionId: string,\n expectedEditGeneration: number,\n input: MaterialDefinitionDraftContent\n) {\n transaction(manager)\n const accepted = content(input)\n await validateMaterialReferences(manager, domainId, accepted)\n const initial = await revision(manager, domainId, revisionId, false)\n const material = await lockSubject(manager, domainId, initial.materialId)\n const draft = await revision(manager, domainId, revisionId)\n if (draft.creatorId !== actorId) refuse('DRAFT_NOT_OWNED')\n if (draft.frozenAt) refuse('REVISION_FROZEN')\n if (draft.baseGeneration !== material.planGeneration) refuse('PLAN_CONFLICT')\n // Moving the effective date across a scheduled boundary changes the before-image.\n const baseRevisionId =\n material.planGeneration > 0\n ? (await resolveMaterialDefinition(manager, domainId, material.id, accepted.effectiveFrom)).revision.id\n : null\n const updated = await manager\n .createQueryBuilder()\n .update(MaterialDefinitionRevision)\n .set({\n ...accepted,\n baseRevision: baseRevisionId ? { id: baseRevisionId } : null,\n editGeneration: expectedEditGeneration + 1\n })\n .where({\n id: revisionId,\n domain: { id: domainId },\n creator: { id: actorId },\n editGeneration: expectedEditGeneration\n })\n .andWhere('frozen_at IS NULL')\n .execute()\n if (updated.affected !== 1) refuse('DRAFT_CONFLICT')\n return revision(manager, domainId, revisionId)\n}\n\n/** Product calls this in the same transaction as issuing its worklist approval. */\nexport async function freezeMaterialDefinitionDraft(\n manager: EntityManager,\n domainId: string,\n actorId: string,\n revisionId: string,\n expectedEditGeneration: number\n) {\n const initial = await revision(manager, domainId, revisionId, false)\n const material = await lockSubject(manager, domainId, initial.materialId)\n const draft = await revision(manager, domainId, revisionId)\n if (draft.creatorId !== actorId) refuse('DRAFT_NOT_OWNED')\n if (draft.frozenAt) refuse('REVISION_FROZEN')\n if (draft.editGeneration !== expectedEditGeneration) refuse('DRAFT_CONFLICT')\n if (draft.baseGeneration !== material.planGeneration) refuse('PLAN_CONFLICT')\n const policy = await masterChangePolicy(manager, domainId, 'materialDefinition')\n if (draft.policyId !== policy.id) refuse('PLAN_CONFLICT')\n materialDraftContent(draft, true)\n await validateMaterialReferences(manager, domainId, draft)\n const contentHash = materialDefinitionSubmissionHash(draft)\n await manager.update(\n MaterialDefinitionRevision,\n { id: revisionId, domain: { id: domainId } },\n { frozenAt: new Date(), contentHash }\n )\n return revision(manager, domainId, revisionId)\n}\n\nexport async function bindMaterialDefinitionApproval(\n manager: EntityManager,\n domainId: string,\n revisionId: string,\n activityInstanceId: string\n) {\n transaction(manager)\n const initial = await revision(manager, domainId, revisionId, false)\n await lockSubject(manager, domainId, initial.materialId)\n const draft = await revision(manager, domainId, revisionId)\n if (!draft.frozenAt || draft.activityInstanceId) refuse('INVALID_SUBMISSION')\n await manager.update(\n MaterialDefinitionRevision,\n { id: revisionId, domain: { id: domainId } },\n { activityInstanceId: text(activityInstanceId, 'activityInstanceId') }\n )\n}\n\n/** Internal completion callback only. Never expose this as an approved=true mutation. */\nexport async function publishMaterialDefinitionRevision(\n manager: EntityManager,\n domainId: string,\n revisionId: string,\n decision: { activityInstanceId: string; approverId: string; submissionHash: string }\n) {\n return publishRevision(manager, domainId, revisionId, {\n kind: 'approved',\n activityInstanceId: decision.activityInstanceId,\n actorId: decision.approverId,\n submissionHash: decision.submissionHash\n })\n}\n\nexport async function publishUnregulatedMaterialDefinition(\n manager: EntityManager,\n domainId: string,\n actorId: string,\n revisionId: string,\n editGeneration: number\n) {\n transaction(manager)\n const initial = await revision(manager, domainId, revisionId, false)\n await lockSubject(manager, domainId, initial.materialId)\n const policy = await masterChangePolicy(manager, domainId, 'materialDefinition')\n if (policy.approvalRequired)\n throw new Refusal('MASTER_APPROVAL_REQUIRED', {}, 'This change requires product approval.')\n const prior = await manager.findOneBy(MaterialDefinitionPlan, {\n domain: { id: domainId },\n publishedRevision: { id: revisionId },\n releaseKind: 'policy'\n })\n if (prior) {\n if (prior.publisherId !== actorId) refuse('DRAFT_NOT_OWNED')\n return prior\n }\n const frozen = await freezeMaterialDefinitionDraft(manager, domainId, actorId, revisionId, editGeneration)\n return publishRevision(manager, domainId, revisionId, { kind: 'policy', actorId, submissionHash: frozen.contentHash })\n}\n\nasync function publishRevision(\n manager: EntityManager,\n domainId: string,\n revisionId: string,\n decision: { kind: 'approved' | 'policy'; activityInstanceId?: string; actorId: string; submissionHash: string }\n) {\n const initial = await revision(manager, domainId, revisionId, false)\n const material = await lockSubject(manager, domainId, initial.materialId)\n const draft = await revision(manager, domainId, revisionId)\n if (\n !draft.frozenAt ||\n (decision.kind === 'approved'\n ? draft.activityInstanceId !== decision.activityInstanceId\n : !!draft.activityInstanceId) ||\n draft.contentHash !== decision.submissionHash ||\n materialDefinitionSubmissionHash(draft) !== decision.submissionHash\n )\n refuse('INVALID_SUBMISSION')\n const policy = await masterChangePolicy(manager, domainId, 'materialDefinition')\n if (draft.policyId !== policy.id) refuse('PLAN_CONFLICT')\n if (policy.approvalRequired !== (decision.kind === 'approved'))\n throw new Refusal('MASTER_APPROVAL_POLICY_MISMATCH', {}, 'Use the publication path required by the domain policy.')\n if (decision.kind === 'approved' && draft.creatorId === decision.actorId) refuse('AUTHOR_CANNOT_APPROVE')\n text(decision.actorId, 'publisher')\n const previousDecision = await manager.findOne(MaterialDefinitionPlan, {\n where: { domain: { id: domainId }, publishedRevision: { id: revisionId } },\n ...currentLock(manager)\n })\n if (previousDecision) return previousDecision\n if (draft.baseGeneration !== material.planGeneration) refuse('PLAN_CONFLICT')\n // Only replacement from effectiveFrom onward is supported in this slice, not arbitrary rescheduling.\n await validateMaterialReferences(manager, domainId, draft)\n if (\n await manager.findOne(MaterialDefinitionBasis, {\n where: { domain: { id: domainId }, material: { id: material.id }, businessTime: MoreThanOrEqual(draft.effectiveFrom) },\n ...currentLock(manager)\n })\n )\n refuse('RETROACTIVE_IMPACT')\n const oldPlan = await manager.findOne(MaterialDefinitionPlan, {\n where: { domain: { id: domainId }, material: { id: material.id }, generation: material.planGeneration },\n ...currentLock(manager)\n })\n if (material.planGeneration > 0 && !oldPlan) refuse('PLAN_CONFLICT')\n const oldSegments = oldPlan\n ? await manager.find(MaterialDefinitionSegment, {\n where: { domain: { id: domainId }, material: { id: material.id }, plan: { id: oldPlan.id } },\n order: { validFrom: 'ASC' },\n ...currentLock(manager)\n })\n : []\n // Do not silently erase an already approved future appointment.\n if (oldSegments.some(segment => segment.validFrom >= draft.effectiveFrom)) refuse('FUTURE_PLAN_CONFLICT')\n const recordedAt = new Date()\n const plan = await manager.save(\n MaterialDefinitionPlan,\n manager.create(MaterialDefinitionPlan, {\n domain: { id: domainId },\n material: { id: material.id },\n generation: material.planGeneration + 1,\n recordedAt,\n activityInstanceId: decision.activityInstanceId ?? null,\n submissionHash: decision.submissionHash,\n approver: decision.kind === 'approved' ? { id: decision.actorId } : null,\n publisher: { id: decision.actorId },\n releaseKind: decision.kind,\n publishedRevision: { id: revisionId },\n policy: { id: policy.id }\n })\n )\n for (const old of oldSegments) {\n await manager.save(\n MaterialDefinitionSegment,\n manager.create(MaterialDefinitionSegment, {\n domain: { id: domainId },\n material: { id: material.id },\n plan: { id: plan.id },\n revision: { id: old.revisionId },\n validFrom: old.validFrom,\n validTo: !old.validTo || old.validTo > draft.effectiveFrom ? draft.effectiveFrom : old.validTo\n })\n )\n }\n await manager.save(\n MaterialDefinitionSegment,\n manager.create(MaterialDefinitionSegment, {\n domain: { id: domainId },\n material: { id: material.id },\n plan: { id: plan.id },\n revision: { id: revisionId },\n validFrom: draft.effectiveFrom,\n validTo: null\n })\n )\n const advanced = await manager.update(\n MaterialDefinition,\n { id: material.id, domain: { id: domainId }, planGeneration: material.planGeneration },\n { planGeneration: plan.generation }\n )\n if (advanced.affected !== 1) refuse('PLAN_CONFLICT')\n return plan\n}\n\nexport async function resolveMaterialDefinition(\n manager: EntityManager,\n domainId: string,\n materialId: string,\n businessTime: Date | string,\n knownAt: Date | string = new Date()\n) {\n const at = instant(businessTime)\n const known = instant(knownAt)\n const plan = await manager.findOne(MaterialDefinitionPlan, {\n where: { domain: { id: domainId }, material: { id: materialId }, recordedAt: LessThanOrEqual(known) },\n order: { generation: 'DESC' },\n ...currentLock(manager)\n })\n if (!plan) refuse('NO_EFFECTIVE_REVISION')\n const query = manager\n .createQueryBuilder(MaterialDefinitionSegment, 'segment')\n .where({ domain: { id: domainId }, material: { id: materialId }, plan: { id: plan.id } })\n .andWhere('segment.validFrom <= :at', { at })\n .andWhere('(segment.validTo IS NULL OR segment.validTo > :at)', { at })\n if (currentLock(manager).lock) query.setLock('pessimistic_write')\n const segments = await query.getMany()\n if (segments.length !== 1) refuse(segments.length ? 'AMBIGUOUS_EFFECTIVITY' : 'NO_EFFECTIVE_REVISION')\n const selected = await revision(manager, domainId, segments[0].revisionId)\n if (!selected.frozenAt || selected.contentHash !== materialDefinitionSubmissionHash(selected))\n refuse('REVISION_INTEGRITY_FAILURE')\n return { revision: selected, plan, segment: segments[0] }\n}\n\n/** Replay reads verify the captured digest too, not only the currently effective schedule. */\nexport async function materialDefinitionRevisionForBasis(manager: EntityManager, domainId: string, basis: MaterialDefinitionBasis) {\n if (basis.domainId !== domainId) refuse('BASIS_CONFLICT')\n const selected = await revision(manager, domainId, basis.revisionId)\n if (selected.materialId !== basis.materialId || !selected.frozenAt || selected.contentHash !== basis.contentHash || materialDefinitionSubmissionHash(selected) !== basis.contentHash) {\n refuse('REVISION_INTEGRITY_FAILURE')\n }\n const plan = await manager.findOneBy(MaterialDefinitionPlan, { id: basis.planId, domain: { id: domainId }, material: { id: basis.materialId } })\n const segments = await manager.findBy(MaterialDefinitionSegment, { domain: { id: domainId }, material: { id: basis.materialId }, plan: { id: basis.planId } })\n const matching = segments.filter(s => s.validFrom <= basis.businessTime && (!s.validTo || s.validTo > basis.businessTime))\n if (!plan || plan.recordedAt > basis.resolvedAt || matching.length !== 1 || matching[0].revisionId !== basis.revisionId) refuse('BASIS_CONFLICT')\n return selected\n}\n\n/** Must run inside the transaction that writes the business record. */\nexport async function captureMaterialDefinitionBasis(\n manager: EntityManager,\n domainId: string,\n materialId: string,\n recordKey: string,\n businessTime: Date | string\n) {\n const at = instant(businessTime)\n await lockSubject(manager, domainId, materialId)\n const existing = await manager.findOne(MaterialDefinitionBasis, {\n where: { domain: { id: domainId }, recordKey },\n ...currentLock(manager)\n })\n if (existing) {\n if (existing.materialId !== materialId || existing.businessTime.getTime() !== at.getTime()) refuse('BASIS_CONFLICT')\n await materialDefinitionRevisionForBasis(manager, domainId, existing)\n return existing\n }\n const resolvedAt = new Date()\n const selected = await resolveMaterialDefinition(manager, domainId, materialId, at, resolvedAt)\n const saved = await manager.save(\n MaterialDefinitionBasis,\n manager.create(MaterialDefinitionBasis, {\n domain: { id: domainId },\n material: { id: materialId },\n recordKey: text(recordKey, 'recordKey'),\n businessTime: at,\n resolvedAt,\n revision: { id: selected.revision.id },\n contentHash: selected.revision.contentHash,\n plan: { id: selected.plan.id }\n })\n )\n return manager.findOneByOrFail(MaterialDefinitionBasis, { id: saved.id, domain: { id: domainId } })\n}\n\nexport async function materialDefinitionRevisionOverview(\n manager: EntityManager,\n domainId: string,\n materialId: string,\n at = new Date()\n) {\n const material = await subject(manager, domainId, materialId)\n const revisions = await manager.find(MaterialDefinitionRevision, {\n where: { domain: { id: domainId }, material: { id: materialId } },\n order: { createdAt: 'ASC', id: 'ASC' }\n })\n const plan = await manager.findOne(MaterialDefinitionPlan, {\n where: { domain: { id: domainId }, material: { id: materialId }, generation: material.planGeneration }\n })\n const schedule = plan\n ? await manager.find(MaterialDefinitionSegment, {\n where: { domain: { id: domainId }, material: { id: materialId }, plan: { id: plan.id } },\n order: { validFrom: 'ASC' }\n })\n : []\n return {\n materialId,\n name: material.name,\n generation: material.planGeneration,\n at: at.toISOString(),\n schedule: schedule.map(segment => ({\n ...segment,\n state: segment.validFrom > at ? 'scheduled' : segment.validTo && segment.validTo <= at ? 'expired' : 'current'\n })),\n revisions: revisions.map(item => ({ ...item, state: item.frozenAt ? 'frozen' : 'draft' }))\n }\n}\n\n/** Read-time projection, never a clock-driven rewrite of the identity row. */\nexport async function effectiveMaterialDefinition(\n manager: EntityManager,\n domainId: string,\n material: MaterialDefinition,\n at = new Date()\n) {\n const selected = await resolveMaterialDefinition(manager, domainId, material.id, at)\n return Object.assign(new MaterialDefinition(), material, {\n revisionNumber: selected.revision.revisionNumber,\n description: selected.revision.description,\n materialClassIds: selected.revision.materialClassIds,\n properties: selected.revision.properties,\n testSpecificationIds: selected.revision.testSpecificationIds,\n effectiveStart: selected.segment.validFrom,\n effectiveEnd: selected.segment.validTo ?? undefined\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"material-revision-service.js","sourceRoot":"","sources":["../../../server/service/material/material-revision-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto'\nimport { EntityManager, LessThanOrEqual, MoreThanOrEqual } from 'typeorm'\nimport { Refusal } from '@things-factory/shell'\nimport { masterChangePolicy } from '../master-change-policy'\nimport { materialDraftContent, validateMaterialReferences } from './material-revision-content'\nimport { MaterialDefinition } from './material-definition'\nimport {\n MaterialDefinitionBasis,\n MaterialDefinitionPlan,\n MaterialDefinitionRevision,\n MaterialDefinitionSegment\n} from './material-revision'\n\nexport class MaterialDefinitionRefusal extends Refusal {\n constructor(code: string, detail?: string) {\n super(\n code,\n {},\n detail ?? MATERIAL_DEFINITION_REFUSALS[code] ?? 'The material definition change could not be applied.'\n )\n }\n}\nconst MATERIAL_DEFINITION_REFUSALS: Record<string, string> = {\n TRANSACTION_REQUIRED: 'This change requires a transaction.',\n INVALID_INSTANT: 'Enter a valid date and time including its time zone.',\n INVALID_CONTENT: 'The proposed material content is invalid.',\n MATERIAL_NOT_FOUND: 'The material does not exist in this domain.',\n REVISION_NOT_FOUND: 'The revision does not exist in this domain.',\n INVALID_BASE_REVISION: 'The proposed change is based on a different revision.',\n DRAFT_NOT_OWNED: 'Only the draft author can edit or submit it.',\n REVISION_FROZEN: 'This submitted revision cannot be edited. Create another draft.',\n DRAFT_CONFLICT: 'The draft changed. Reload it before saving.',\n PLAN_CONFLICT: 'The approved schedule changed. Review and submit a new draft.',\n INVALID_SUBMISSION: 'The submitted content does not match the frozen revision.',\n AUTHOR_CANNOT_APPROVE: 'The author cannot approve their own change.',\n RETROACTIVE_IMPACT: 'This change would alter material definitions already used by recorded transactions.',\n FUTURE_PLAN_CONFLICT: 'This change conflicts with an approved future schedule.',\n NO_EFFECTIVE_REVISION: 'There is no published revision effective at the business time.',\n AMBIGUOUS_EFFECTIVITY: 'More than one revision is effective at the business time.',\n REVISION_INTEGRITY_FAILURE: 'The stored revision does not match its signed content.',\n BASIS_CONFLICT: 'This transaction already has a different material or business time.',\n APPROVAL_LINE_REQUIRED: 'Configure an approval line before submitting this change.',\n REVISION_REQUIRED: 'Change the material through a revision draft.'\n}\nfunction refuse(code: string, detail?: string): never {\n throw new MaterialDefinitionRefusal(code, detail)\n}\nfunction transaction(manager: EntityManager) {\n if (!manager.queryRunner?.isTransactionActive) refuse('TRANSACTION_REQUIRED')\n}\n/** Current reads are required after waiting for the subject lock, including MySQL REPEATABLE READ. */\nfunction currentLock(manager: EntityManager) {\n const driver = manager.connection.options.type\n return manager.queryRunner?.isTransactionActive && !['sqlite', 'better-sqlite3', 'sqljs'].includes(driver)\n ? { lock: { mode: 'pessimistic_write' as const } }\n : {}\n}\nfunction instant(value: Date | string): Date {\n if (!(value instanceof Date) && (typeof value !== 'string' || !/(Z|[+-]\\d{2}:\\d{2})$/.test(value)))\n refuse('INVALID_INSTANT')\n const result = new Date(value)\n if (!Number.isFinite(result.getTime())) refuse('INVALID_INSTANT')\n return result\n}\nfunction text(value: unknown, field: string): string {\n if (typeof value !== 'string' || !value.trim()) refuse('INVALID_CONTENT', field)\n return value.trim()\n}\n/** Sorted object keys, ordered arrays, ISO instants. This is the v1 submission encoding. */\nfunction canonical(value: any): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value)\n if (Array.isArray(value)) return '[' + value.map(canonical).join(',') + ']'\n return (\n '{' +\n Object.keys(value)\n .sort()\n .map(key => JSON.stringify(key) + ':' + canonical(value[key]))\n .join(',') +\n '}'\n )\n}\nexport function materialDefinitionSubmissionHash(revision: MaterialDefinitionRevision): string {\n return createHash('sha256')\n .update(\n canonical({\n schemaVersion: 1,\n revisionNumber: revision.revisionNumber,\n policyId: revision.policyId,\n domainId: revision.domainId,\n materialId: revision.materialId,\n baseRevisionId: revision.baseRevisionId,\n baseGeneration: revision.baseGeneration,\n description: revision.description,\n materialClassIds: revision.materialClassIds,\n properties: revision.properties,\n testSpecificationIds: revision.testSpecificationIds,\n effectiveFrom: revision.effectiveFrom.toISOString(),\n reason: revision.reason\n })\n )\n .digest('hex')\n}\n\n/** Display values are a checked projection of the frozen revision, never a second editable source. */\nexport async function materialDefinitionApprovalInput(manager: EntityManager, domainId: string, revisionId: string) {\n const draft = await revision(manager, domainId, revisionId)\n if (!draft.frozenAt || draft.contentHash !== materialDefinitionSubmissionHash(draft)) refuse('INVALID_SUBMISSION')\n const material = await subject(manager, domainId, draft.materialId)\n const base = draft.baseRevisionId ? await revision(manager, domainId, draft.baseRevisionId) : null\n const plan = base ? await manager.findOneBy(MaterialDefinitionPlan, {\n domain: { id: domainId }, material: { id: draft.materialId }, generation: draft.baseGeneration\n }) : null\n const segment = plan && base ? await manager.findOneBy(MaterialDefinitionSegment, {\n domain: { id: domainId }, plan: { id: plan.id }, revision: { id: base.id }\n }) : null\n const values = (row: MaterialDefinitionRevision) => ({\n revisionNumber: row.revisionNumber,\n detail: {\n revisionId: row.id, createdAt: row.createdAt.toISOString(), frozenAt: row.frozenAt?.toISOString(),\n effectiveFrom: row.effectiveFrom.toISOString(), reason: row.reason,\n ...(row.id === base?.id && segment ? { validFrom: segment.validFrom.toISOString(), validTo: segment.validTo?.toISOString() ?? null } : {})\n },\n description: row.description,\n materialClassIds: row.materialClassIds,\n properties: row.properties,\n testSpecificationIds: row.testSpecificationIds\n })\n return {\n headline: material.name,\n reason: draft.reason,\n effectiveFrom: draft.effectiveFrom.toISOString(),\n before: base ? values(base) : null,\n after: values(draft),\n revision: {\n revisionId: draft.id,\n hash: draft.contentHash,\n materialId: draft.materialId,\n baseGeneration: draft.baseGeneration\n }\n }\n}\n\nexport async function assertMaterialDefinitionApprovalInput(\n manager: EntityManager,\n domainId: string,\n input: Record<string, unknown>\n) {\n const reference = input?.revision as { revisionId?: string }\n if (typeof reference?.revisionId !== 'string') refuse('INVALID_SUBMISSION')\n const expected = await materialDefinitionApprovalInput(manager, domainId, reference.revisionId)\n for (const key of Object.keys(expected)) {\n if (canonical(input[key]) !== canonical(expected[key])) refuse('INVALID_SUBMISSION')\n }\n}\n\nexport interface MaterialDefinitionDraftContent {\n description?: string\n materialClassIds?: string[]\n properties?: Record<string, unknown>[]\n testSpecificationIds?: string[]\n effectiveFrom: Date | string\n reason: string\n}\nfunction content(input: MaterialDefinitionDraftContent) {\n return { ...materialDraftContent(input), effectiveFrom: instant(input.effectiveFrom), reason: text(input.reason, 'reason') }\n}\nasync function subject(manager: EntityManager, domainId: string, materialId: string) {\n const material = await manager.findOne(MaterialDefinition, {\n where: { id: materialId, domain: { id: domainId } },\n ...currentLock(manager)\n })\n if (!material) refuse('MATERIAL_NOT_FOUND')\n // Compare the current head and latest persisted plan in one SQL snapshot. A historical\n // knownAt query must not compare its selected old plan with the current head.\n const head = await manager.createQueryBuilder(MaterialDefinition, 'head')\n .leftJoin(MaterialDefinitionPlan, 'plan', 'plan.material = head.id AND plan.domain = head.domain')\n .select('head.planGeneration', 'generation')\n .addSelect('MAX(plan.generation)', 'latest')\n .where({ id: materialId, domain: { id: domainId } })\n .groupBy('head.id').addGroupBy('head.planGeneration')\n .getRawOne()\n if (!head || Number(head.generation) !== Number(head.latest ?? 0)) {\n throw new Refusal('PLAN_INTEGRITY_FAILURE', {}, 'The current plan generation does not match the latest published plan. Contact an administrator.')\n }\n return material\n}\nasync function revision(manager: EntityManager, domainId: string, revisionId: string, locked = true) {\n const found = await manager.findOne(MaterialDefinitionRevision, {\n where: { id: revisionId, domain: { id: domainId } },\n ...(locked ? currentLock(manager) : {})\n })\n if (!found) refuse('REVISION_NOT_FOUND')\n return found\n}\n/** A write lock valid on every supported SQL backend, including SQLite (no SELECT FOR UPDATE). */\nasync function lockSubject(manager: EntityManager, domainId: string, materialId: string) {\n transaction(manager)\n const locked = await manager\n .createQueryBuilder()\n .update(MaterialDefinition)\n .set({ revisionLock: () => 'revision_lock + 1' })\n .where({ id: materialId, domain: { id: domainId } })\n .execute()\n if (locked.affected !== 1) refuse('MATERIAL_NOT_FOUND')\n return subject(manager, domainId, materialId)\n}\n\nexport async function createMaterialDefinitionDraft(\n manager: EntityManager,\n domainId: string,\n creatorId: string,\n asked: { materialId?: string; name?: string; baseRevisionId?: string; content: MaterialDefinitionDraftContent }\n) {\n transaction(manager)\n const accepted = content(asked.content)\n await validateMaterialReferences(manager, domainId, accepted)\n const policy = await masterChangePolicy(manager, domainId, 'materialDefinition')\n let material: MaterialDefinition\n if (asked.materialId) {\n material = await lockSubject(manager, domainId, asked.materialId)\n } else {\n material = await manager.save(\n MaterialDefinition,\n manager.create(MaterialDefinition, {\n domain: { id: domainId },\n name: text(asked.name, 'name'),\n planGeneration: 0,\n revisionLock: 0,\n creator: { id: creatorId },\n updater: { id: creatorId }\n })\n )\n }\n const previous = await manager.findOne(MaterialDefinitionRevision, {\n where: { domain: { id: domainId }, material: { id: material.id } }, order: { revisionNumber: 'DESC' },\n ...currentLock(manager)\n })\n const revisionNumber = (previous?.revisionNumber ?? 0) + 1\n let baseRevisionId: string | null = null\n if (material.planGeneration > 0) {\n baseRevisionId = (await resolveMaterialDefinition(manager, domainId, material.id, accepted.effectiveFrom)).revision.id\n }\n if (asked.baseRevisionId && asked.baseRevisionId !== baseRevisionId) refuse('INVALID_BASE_REVISION')\n const saved = await manager.save(\n MaterialDefinitionRevision,\n manager.create(MaterialDefinitionRevision, {\n ...accepted,\n policy: { id: policy.id },\n domain: { id: domainId },\n material: { id: material.id },\n baseRevision: baseRevisionId ? { id: baseRevisionId } : null,\n baseGeneration: material.planGeneration,\n revisionNumber,\n editGeneration: 0,\n creator: { id: creatorId },\n createdAt: new Date(),\n frozenAt: null,\n contentHash: null,\n activityInstanceId: null\n })\n )\n return revision(manager, domainId, saved.id)\n}\n\nexport async function editMaterialDefinitionDraft(\n manager: EntityManager,\n domainId: string,\n actorId: string,\n revisionId: string,\n expectedEditGeneration: number,\n input: MaterialDefinitionDraftContent\n) {\n transaction(manager)\n const accepted = content(input)\n await validateMaterialReferences(manager, domainId, accepted)\n const initial = await revision(manager, domainId, revisionId, false)\n const material = await lockSubject(manager, domainId, initial.materialId)\n const draft = await revision(manager, domainId, revisionId)\n if (draft.creatorId !== actorId) refuse('DRAFT_NOT_OWNED')\n if (draft.frozenAt) refuse('REVISION_FROZEN')\n if (draft.baseGeneration !== material.planGeneration) refuse('PLAN_CONFLICT')\n // Moving the effective date across a scheduled boundary changes the before-image.\n const baseRevisionId =\n material.planGeneration > 0\n ? (await resolveMaterialDefinition(manager, domainId, material.id, accepted.effectiveFrom)).revision.id\n : null\n const updated = await manager\n .createQueryBuilder()\n .update(MaterialDefinitionRevision)\n .set({\n ...accepted,\n baseRevision: baseRevisionId ? { id: baseRevisionId } : null,\n editGeneration: expectedEditGeneration + 1\n })\n .where({\n id: revisionId,\n domain: { id: domainId },\n creator: { id: actorId },\n editGeneration: expectedEditGeneration\n })\n .andWhere('frozen_at IS NULL')\n .execute()\n if (updated.affected !== 1) refuse('DRAFT_CONFLICT')\n return revision(manager, domainId, revisionId)\n}\n\n/** Product calls this in the same transaction as issuing its worklist approval. */\nexport async function freezeMaterialDefinitionDraft(\n manager: EntityManager,\n domainId: string,\n actorId: string,\n revisionId: string,\n expectedEditGeneration: number\n) {\n const initial = await revision(manager, domainId, revisionId, false)\n const material = await lockSubject(manager, domainId, initial.materialId)\n const draft = await revision(manager, domainId, revisionId)\n if (draft.creatorId !== actorId) refuse('DRAFT_NOT_OWNED')\n if (draft.frozenAt) refuse('REVISION_FROZEN')\n if (draft.editGeneration !== expectedEditGeneration) refuse('DRAFT_CONFLICT')\n if (draft.baseGeneration !== material.planGeneration) refuse('PLAN_CONFLICT')\n const policy = await masterChangePolicy(manager, domainId, 'materialDefinition')\n if (draft.policyId !== policy.id) refuse('PLAN_CONFLICT')\n materialDraftContent(draft, true)\n await validateMaterialReferences(manager, domainId, draft)\n const contentHash = materialDefinitionSubmissionHash(draft)\n await manager.update(\n MaterialDefinitionRevision,\n { id: revisionId, domain: { id: domainId } },\n { frozenAt: new Date(), contentHash }\n )\n return revision(manager, domainId, revisionId)\n}\n\nexport async function bindMaterialDefinitionApproval(\n manager: EntityManager,\n domainId: string,\n revisionId: string,\n activityInstanceId: string\n) {\n transaction(manager)\n const initial = await revision(manager, domainId, revisionId, false)\n await lockSubject(manager, domainId, initial.materialId)\n const draft = await revision(manager, domainId, revisionId)\n if (!draft.frozenAt || draft.activityInstanceId) refuse('INVALID_SUBMISSION')\n await manager.update(\n MaterialDefinitionRevision,\n { id: revisionId, domain: { id: domainId } },\n { activityInstanceId: text(activityInstanceId, 'activityInstanceId') }\n )\n}\n\n/** Internal completion callback only. Never expose this as an approved=true mutation. */\nexport async function publishMaterialDefinitionRevision(\n manager: EntityManager,\n domainId: string,\n revisionId: string,\n decision: { activityInstanceId: string; approverId: string; submissionHash: string }\n) {\n return publishRevision(manager, domainId, revisionId, {\n kind: 'approved',\n activityInstanceId: decision.activityInstanceId,\n actorId: decision.approverId,\n submissionHash: decision.submissionHash\n })\n}\n\nexport async function publishUnregulatedMaterialDefinition(\n manager: EntityManager,\n domainId: string,\n actorId: string,\n revisionId: string,\n editGeneration: number\n) {\n transaction(manager)\n const initial = await revision(manager, domainId, revisionId, false)\n await lockSubject(manager, domainId, initial.materialId)\n const policy = await masterChangePolicy(manager, domainId, 'materialDefinition')\n if (policy.approvalRequired)\n throw new Refusal('MASTER_APPROVAL_REQUIRED', {}, 'This change requires product approval.')\n const prior = await manager.findOneBy(MaterialDefinitionPlan, {\n domain: { id: domainId },\n publishedRevision: { id: revisionId },\n releaseKind: 'policy'\n })\n if (prior) {\n if (prior.publisherId !== actorId) refuse('DRAFT_NOT_OWNED')\n return prior\n }\n const frozen = await freezeMaterialDefinitionDraft(manager, domainId, actorId, revisionId, editGeneration)\n return publishRevision(manager, domainId, revisionId, { kind: 'policy', actorId, submissionHash: frozen.contentHash })\n}\n\nasync function publishRevision(\n manager: EntityManager,\n domainId: string,\n revisionId: string,\n decision: { kind: 'approved' | 'policy'; activityInstanceId?: string; actorId: string; submissionHash: string }\n) {\n const initial = await revision(manager, domainId, revisionId, false)\n const material = await lockSubject(manager, domainId, initial.materialId)\n const draft = await revision(manager, domainId, revisionId)\n if (\n !draft.frozenAt ||\n (decision.kind === 'approved'\n ? draft.activityInstanceId !== decision.activityInstanceId\n : !!draft.activityInstanceId) ||\n draft.contentHash !== decision.submissionHash ||\n materialDefinitionSubmissionHash(draft) !== decision.submissionHash\n )\n refuse('INVALID_SUBMISSION')\n const policy = await masterChangePolicy(manager, domainId, 'materialDefinition')\n if (draft.policyId !== policy.id) refuse('PLAN_CONFLICT')\n if (policy.approvalRequired !== (decision.kind === 'approved'))\n throw new Refusal('MASTER_APPROVAL_POLICY_MISMATCH', {}, 'Use the publication path required by the domain policy.')\n if (decision.kind === 'approved' && draft.creatorId === decision.actorId) refuse('AUTHOR_CANNOT_APPROVE')\n text(decision.actorId, 'publisher')\n const previousDecision = await manager.findOne(MaterialDefinitionPlan, {\n where: { domain: { id: domainId }, publishedRevision: { id: revisionId } },\n ...currentLock(manager)\n })\n if (previousDecision) return previousDecision\n if (draft.baseGeneration !== material.planGeneration) refuse('PLAN_CONFLICT')\n // Only replacement from effectiveFrom onward is supported in this slice, not arbitrary rescheduling.\n await validateMaterialReferences(manager, domainId, draft)\n if (\n await manager.findOne(MaterialDefinitionBasis, {\n where: { domain: { id: domainId }, material: { id: material.id }, businessTime: MoreThanOrEqual(draft.effectiveFrom) },\n ...currentLock(manager)\n })\n )\n refuse('RETROACTIVE_IMPACT')\n const oldPlan = await manager.findOne(MaterialDefinitionPlan, {\n where: { domain: { id: domainId }, material: { id: material.id }, generation: material.planGeneration },\n ...currentLock(manager)\n })\n if (material.planGeneration > 0 && !oldPlan) refuse('PLAN_CONFLICT')\n const oldSegments = oldPlan\n ? await manager.find(MaterialDefinitionSegment, {\n where: { domain: { id: domainId }, material: { id: material.id }, plan: { id: oldPlan.id } },\n order: { validFrom: 'ASC' },\n ...currentLock(manager)\n })\n : []\n // Do not silently erase an already approved future appointment.\n if (oldSegments.some(segment => segment.validFrom >= draft.effectiveFrom)) refuse('FUTURE_PLAN_CONFLICT')\n const recordedAt = new Date()\n const plan = await manager.save(\n MaterialDefinitionPlan,\n manager.create(MaterialDefinitionPlan, {\n domain: { id: domainId },\n material: { id: material.id },\n generation: material.planGeneration + 1,\n recordedAt,\n activityInstanceId: decision.activityInstanceId ?? null,\n submissionHash: decision.submissionHash,\n approver: decision.kind === 'approved' ? { id: decision.actorId } : null,\n publisher: { id: decision.actorId },\n releaseKind: decision.kind,\n publishedRevision: { id: revisionId },\n policy: { id: policy.id }\n })\n )\n for (const old of oldSegments) {\n await manager.save(\n MaterialDefinitionSegment,\n manager.create(MaterialDefinitionSegment, {\n domain: { id: domainId },\n material: { id: material.id },\n plan: { id: plan.id },\n revision: { id: old.revisionId },\n validFrom: old.validFrom,\n validTo: !old.validTo || old.validTo > draft.effectiveFrom ? draft.effectiveFrom : old.validTo\n })\n )\n }\n await manager.save(\n MaterialDefinitionSegment,\n manager.create(MaterialDefinitionSegment, {\n domain: { id: domainId },\n material: { id: material.id },\n plan: { id: plan.id },\n revision: { id: revisionId },\n validFrom: draft.effectiveFrom,\n validTo: null\n })\n )\n const advanced = await manager.update(\n MaterialDefinition,\n { id: material.id, domain: { id: domainId }, planGeneration: material.planGeneration },\n { planGeneration: plan.generation }\n )\n if (advanced.affected !== 1) refuse('PLAN_CONFLICT')\n return plan\n}\n\nexport async function resolveMaterialDefinition(\n manager: EntityManager,\n domainId: string,\n materialId: string,\n businessTime: Date | string,\n knownAt: Date | string = new Date()\n) {\n const at = instant(businessTime)\n const known = instant(knownAt)\n const plan = await manager.findOne(MaterialDefinitionPlan, {\n where: { domain: { id: domainId }, material: { id: materialId }, recordedAt: LessThanOrEqual(known) },\n order: { generation: 'DESC' },\n ...currentLock(manager)\n })\n if (!plan) refuse('NO_EFFECTIVE_REVISION')\n await subject(manager, domainId, materialId)\n const query = manager\n .createQueryBuilder(MaterialDefinitionSegment, 'segment')\n .where({ domain: { id: domainId }, material: { id: materialId }, plan: { id: plan.id } })\n .andWhere('segment.validFrom <= :at', { at })\n .andWhere('(segment.validTo IS NULL OR segment.validTo > :at)', { at })\n if (currentLock(manager).lock) query.setLock('pessimistic_write')\n const segments = await query.getMany()\n if (segments.length !== 1) refuse(segments.length ? 'AMBIGUOUS_EFFECTIVITY' : 'NO_EFFECTIVE_REVISION')\n const selected = await revision(manager, domainId, segments[0].revisionId)\n if (!selected.frozenAt || selected.contentHash !== materialDefinitionSubmissionHash(selected))\n refuse('REVISION_INTEGRITY_FAILURE')\n return { revision: selected, plan, segment: segments[0] }\n}\n\n/** Replay reads verify the captured digest too, not only the currently effective schedule. */\nexport async function materialDefinitionRevisionForBasis(manager: EntityManager, domainId: string, basis: MaterialDefinitionBasis) {\n if (basis.domainId !== domainId) refuse('BASIS_CONFLICT')\n const selected = await revision(manager, domainId, basis.revisionId)\n if (selected.materialId !== basis.materialId || !selected.frozenAt || selected.contentHash !== basis.contentHash || materialDefinitionSubmissionHash(selected) !== basis.contentHash) {\n refuse('REVISION_INTEGRITY_FAILURE')\n }\n const plan = await manager.findOneBy(MaterialDefinitionPlan, { id: basis.planId, domain: { id: domainId }, material: { id: basis.materialId } })\n const segments = await manager.findBy(MaterialDefinitionSegment, { domain: { id: domainId }, material: { id: basis.materialId }, plan: { id: basis.planId } })\n const matching = segments.filter(s => s.validFrom <= basis.businessTime && (!s.validTo || s.validTo > basis.businessTime))\n if (!plan || plan.recordedAt > basis.resolvedAt || matching.length !== 1 || matching[0].revisionId !== basis.revisionId) refuse('BASIS_CONFLICT')\n return selected\n}\n\n/** Must run inside the transaction that writes the business record. */\nexport async function captureMaterialDefinitionBasis(\n manager: EntityManager,\n domainId: string,\n materialId: string,\n recordKey: string,\n businessTime: Date | string\n) {\n const at = instant(businessTime)\n await lockSubject(manager, domainId, materialId)\n const existing = await manager.findOne(MaterialDefinitionBasis, {\n where: { domain: { id: domainId }, recordKey },\n ...currentLock(manager)\n })\n if (existing) {\n if (existing.materialId !== materialId || existing.businessTime.getTime() !== at.getTime()) refuse('BASIS_CONFLICT')\n await materialDefinitionRevisionForBasis(manager, domainId, existing)\n return existing\n }\n const resolvedAt = new Date()\n const selected = await resolveMaterialDefinition(manager, domainId, materialId, at, resolvedAt)\n const saved = await manager.save(\n MaterialDefinitionBasis,\n manager.create(MaterialDefinitionBasis, {\n domain: { id: domainId },\n material: { id: materialId },\n recordKey: text(recordKey, 'recordKey'),\n businessTime: at,\n resolvedAt,\n revision: { id: selected.revision.id },\n contentHash: selected.revision.contentHash,\n plan: { id: selected.plan.id }\n })\n )\n return manager.findOneByOrFail(MaterialDefinitionBasis, { id: saved.id, domain: { id: domainId } })\n}\n\nexport async function materialDefinitionRevisionOverview(\n manager: EntityManager,\n domainId: string,\n materialId: string,\n at = new Date()\n) {\n const material = await subject(manager, domainId, materialId)\n const revisions = await manager.find(MaterialDefinitionRevision, {\n where: { domain: { id: domainId }, material: { id: materialId } },\n order: { createdAt: 'ASC', id: 'ASC' }\n })\n const plan = await manager.findOne(MaterialDefinitionPlan, {\n where: { domain: { id: domainId }, material: { id: materialId }, generation: material.planGeneration }\n })\n const schedule = plan\n ? await manager.find(MaterialDefinitionSegment, {\n where: { domain: { id: domainId }, material: { id: materialId }, plan: { id: plan.id } },\n order: { validFrom: 'ASC' }\n })\n : []\n return {\n materialId,\n name: material.name,\n generation: material.planGeneration,\n at: at.toISOString(),\n schedule: schedule.map(segment => ({\n ...segment,\n state: segment.validFrom > at ? 'scheduled' : segment.validTo && segment.validTo <= at ? 'expired' : 'current'\n })),\n revisions: revisions.map(item => ({ ...item, state: item.frozenAt ? 'frozen' : 'draft' }))\n }\n}\n\n/** Read-time projection, never a clock-driven rewrite of the identity row. */\nexport async function effectiveMaterialDefinition(\n manager: EntityManager,\n domainId: string,\n material: MaterialDefinition,\n at = new Date()\n) {\n const selected = await resolveMaterialDefinition(manager, domainId, material.id, at)\n return Object.assign(new MaterialDefinition(), material, {\n revisionNumber: selected.revision.revisionNumber,\n description: selected.revision.description,\n materialClassIds: selected.revision.materialClassIds,\n properties: selected.revision.properties,\n testSpecificationIds: selected.revision.testSpecificationIds,\n effectiveStart: selected.segment.validFrom,\n effectiveEnd: selected.segment.validTo ?? undefined\n })\n}\n"]}
|
|
@@ -203,6 +203,18 @@ async function subject(manager, domainId, recipeId) {
|
|
|
203
203
|
});
|
|
204
204
|
if (!recipe)
|
|
205
205
|
refuse('RECIPE_NOT_FOUND');
|
|
206
|
+
// Compare the current head and latest persisted plan in one SQL snapshot. A historical
|
|
207
|
+
// knownAt query must not compare its selected old plan with the current head.
|
|
208
|
+
const head = await manager.createQueryBuilder(recipe_definition_1.RecipeDefinition, 'head')
|
|
209
|
+
.leftJoin(recipe_revision_1.RecipePlan, 'plan', 'plan.recipe = head.id AND plan.domain = head.domain')
|
|
210
|
+
.select('head.planGeneration', 'generation')
|
|
211
|
+
.addSelect('MAX(plan.generation)', 'latest')
|
|
212
|
+
.where({ id: recipeId, domain: { id: domainId } })
|
|
213
|
+
.groupBy('head.id').addGroupBy('head.planGeneration')
|
|
214
|
+
.getRawOne();
|
|
215
|
+
if (!head || Number(head.generation) !== Number(head.latest ?? 0)) {
|
|
216
|
+
throw new shell_1.Refusal('PLAN_INTEGRITY_FAILURE', {}, 'The current plan generation does not match the latest published plan. Contact an administrator.');
|
|
217
|
+
}
|
|
206
218
|
return recipe;
|
|
207
219
|
}
|
|
208
220
|
async function revision(manager, domainId, revisionId, locked = true) {
|
|
@@ -478,6 +490,7 @@ async function resolveRecipe(manager, domainId, recipeId, businessTime, knownAt
|
|
|
478
490
|
});
|
|
479
491
|
if (!plan)
|
|
480
492
|
refuse('NO_EFFECTIVE_REVISION');
|
|
493
|
+
await subject(manager, domainId, recipeId);
|
|
481
494
|
const query = manager
|
|
482
495
|
.createQueryBuilder(recipe_revision_1.RecipeSegment, 'segment')
|
|
483
496
|
.where({ domain: { id: domainId }, recipe: { id: recipeId }, plan: { id: plan.id } })
|