@things-factory/work-shift 10.1.37 → 10.1.38
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/work-shift.js +4 -1
- package/dist-client/pages/work-shift.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/index.js +9 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/service/index.d.ts +2 -1
- package/dist-server/service/index.js +1 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/work-shift/index.d.ts +1 -1
- package/dist-server/service/work-shift/work-shift-baseline.d.ts +23 -0
- package/dist-server/service/work-shift/work-shift-baseline.js +54 -0
- package/dist-server/service/work-shift/work-shift-baseline.js.map +1 -0
- package/dist-server/service/work-shift/work-shift-content.d.ts +3 -0
- package/dist-server/service/work-shift/work-shift-content.js +7 -0
- package/dist-server/service/work-shift/work-shift-content.js.map +1 -1
- package/dist-server/service/work-shift/work-shift-lifecycle-resolver.d.ts +9 -2
- package/dist-server/service/work-shift/work-shift-lifecycle-resolver.js +16 -6
- package/dist-server/service/work-shift/work-shift-lifecycle-resolver.js.map +1 -1
- package/dist-server/service/work-shift/work-shift-lifecycle.d.ts +98 -5
- package/dist-server/service/work-shift/work-shift-lifecycle.js +133 -0
- package/dist-server/service/work-shift/work-shift-lifecycle.js.map +1 -1
- package/dist-server/service/work-shift/work-shift-revision-service.d.ts +1 -2
- package/dist-server/service/work-shift/work-shift-revision-service.js +10 -7
- package/dist-server/service/work-shift/work-shift-revision-service.js.map +1 -1
- package/dist-server/service/work-shift/work-shift-revision.d.ts +7 -5
- package/dist-server/service/work-shift/work-shift-revision.js +2 -2
- package/dist-server/service/work-shift/work-shift-revision.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
package/dist-server/index.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
const shell_1 = require("@things-factory/shell");
|
|
5
|
+
const work_shift_baseline_1 = require("./service/work-shift/work-shift-baseline");
|
|
4
6
|
tslib_1.__exportStar(require("./controllers"), exports);
|
|
5
7
|
tslib_1.__exportStar(require("./service"), exports);
|
|
8
|
+
/*
|
|
9
|
+
* 판을 올린 설치본의 교대에 첫 편성 개정본을 세운다(2026-09-24). 이미 있으면 손대지 않으므로 기동마다
|
|
10
|
+
* 불러도 된다. 무엇이 실패해도 던지지 않는다 — 서버를 반쯤 뜬 채로 두지 않는다(§`work-shift-baseline`).
|
|
11
|
+
*/
|
|
12
|
+
process.on('bootstrap-module-start', () => {
|
|
13
|
+
(0, work_shift_baseline_1.standWorkShiftBaselinesAtBoot)((0, shell_1.getDataSource)()).catch(error => console.error(`[work-shift] 교대 기준선을 세우지 못했습니다 — ${error?.message ?? error}`));
|
|
14
|
+
});
|
|
6
15
|
//# sourceMappingURL=index.js.map
|
package/dist-server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,wDAA6B;AAC7B,oDAAyB","sourcesContent":["
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,iDAAqD;AAErD,kFAAwF;AAExF,wDAA6B;AAC7B,oDAAyB;AAEzB;;;GAGG;AACH,OAAO,CAAC,EAAE,CAAC,wBAA+B,EAAE,GAAG,EAAE;IAC/C,IAAA,mDAA6B,EAAC,IAAA,qBAAa,GAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAC3D,OAAO,CAAC,KAAK,CAAC,oCAAoC,KAAK,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC,CAC7E,CAAA;AACH,CAAC,CAAC,CAAA","sourcesContent":["import { getDataSource } from '@things-factory/shell'\n\nimport { standWorkShiftBaselinesAtBoot } from './service/work-shift/work-shift-baseline'\n\nexport * from './controllers'\nexport * from './service'\n\n/*\n * 판을 올린 설치본의 교대에 첫 편성 개정본을 세운다(2026-09-24). 이미 있으면 손대지 않으므로 기동마다\n * 불러도 된다. 무엇이 실패해도 던지지 않는다 — 서버를 반쯤 뜬 채로 두지 않는다(§`work-shift-baseline`).\n */\nprocess.on('bootstrap-module-start' as any, () => {\n standWorkShiftBaselinesAtBoot(getDataSource()).catch(error =>\n console.error(`[work-shift] 교대 기준선을 세우지 못했습니다 — ${error?.message ?? error}`)\n )\n})\n"]}
|
|
@@ -4,8 +4,9 @@ export * from './work-shift/work-shift-revision-service';
|
|
|
4
4
|
export * from './work-shift/work-shift-lifecycle';
|
|
5
5
|
export * from './work-shift/work-shift-arrangement';
|
|
6
6
|
export * from './work-shift/work-shift-content';
|
|
7
|
+
export * from './work-shift/work-shift-baseline';
|
|
7
8
|
export * from './work-shift/days-of-week';
|
|
8
|
-
export declare const entities: (typeof import("./work-shift/work-shift
|
|
9
|
+
export declare const entities: (typeof import("./work-shift/work-shift").WorkShift | typeof import("./work-shift/work-shift-revision").WorkShiftRevision | typeof import("./work-shift/work-shift-revision").WorkShiftPlan | typeof import("./work-shift/work-shift-revision").WorkShiftSegment | typeof import("./work-shift/work-shift-revision").WorkShiftBasis | typeof import("./work-shift/work-shift-arrangement").WorkShiftArrangement)[];
|
|
9
10
|
export declare const schema: {
|
|
10
11
|
resolverClasses: (typeof import("./work-shift/work-shift-query").DomainWorkShiftQuery | typeof import("./work-shift/work-shift-query").WorkShiftQuery | typeof import("./work-shift/work-shift-mutation").WorkShiftMutation | typeof import("./work-shift/work-shift-lifecycle-resolver").WorkShiftLifecycleResolver)[];
|
|
11
12
|
};
|
|
@@ -9,6 +9,7 @@ tslib_1.__exportStar(require("./work-shift/work-shift-revision-service"), export
|
|
|
9
9
|
tslib_1.__exportStar(require("./work-shift/work-shift-lifecycle"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./work-shift/work-shift-arrangement"), exports);
|
|
11
11
|
tslib_1.__exportStar(require("./work-shift/work-shift-content"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./work-shift/work-shift-baseline"), exports);
|
|
12
13
|
/*
|
|
13
14
|
* This file names each source file rather than re-exporting the folder barrel, so anything added
|
|
14
15
|
* to that barrel stops at the package boundary unless it is also listed here. `daysOfWeek` is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yBAAyB;AACzB,kEAAuC;AACvC,2EAAgD;AAChD,mFAAwD;AACxD,4EAAiD;AACjD,8EAAmD;AACnD,0EAA+C;AAC/C;;;;;GAKG;AACH,oEAAyC;AAEzC,mCAAmC;AACnC,6CAA6F;AAEhF,QAAA,QAAQ,GAAG;IACtB,cAAc;IACf,GAAG,qBAAiB;CACpB,CAAA;AAGY,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,sBAAsB;QACxB,GAAG,sBAAkB;KACpB;CACF,CAAA","sourcesContent":["/* EXPORT ENTITY TYPES */\nexport * from './work-shift/work-shift'\nexport * from './work-shift/work-shift-revision'\nexport * from './work-shift/work-shift-revision-service'\nexport * from './work-shift/work-shift-lifecycle'\nexport * from './work-shift/work-shift-arrangement'\nexport * from './work-shift/work-shift-content'\n/*\n * This file names each source file rather than re-exporting the folder barrel, so anything added\n * to that barrel stops at the package boundary unless it is also listed here. `daysOfWeek` is\n * stored as a CSV and every consumer has to parse it, so the parser has to be reachable — a\n * consumer that cannot import it writes its own, and the two disagree quietly.\n */\nexport * from './work-shift/days-of-week'\n\n/* IMPORT ENTITIES AND RESOLVERS */\nimport { entities as WorkShiftEntities, resolvers as WorkShiftResolvers } from './work-shift'\n\nexport const entities = [ \n /* ENTITIES */\n\t...WorkShiftEntities,\n] \n\n\nexport const schema = {\n resolverClasses: [\n /* RESOLVER CLASSES */\n\t\t...WorkShiftResolvers,\n ] \n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yBAAyB;AACzB,kEAAuC;AACvC,2EAAgD;AAChD,mFAAwD;AACxD,4EAAiD;AACjD,8EAAmD;AACnD,0EAA+C;AAC/C,2EAAgD;AAChD;;;;;GAKG;AACH,oEAAyC;AAEzC,mCAAmC;AACnC,6CAA6F;AAEhF,QAAA,QAAQ,GAAG;IACtB,cAAc;IACf,GAAG,qBAAiB;CACpB,CAAA;AAGY,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,sBAAsB;QACxB,GAAG,sBAAkB;KACpB;CACF,CAAA","sourcesContent":["/* EXPORT ENTITY TYPES */\nexport * from './work-shift/work-shift'\nexport * from './work-shift/work-shift-revision'\nexport * from './work-shift/work-shift-revision-service'\nexport * from './work-shift/work-shift-lifecycle'\nexport * from './work-shift/work-shift-arrangement'\nexport * from './work-shift/work-shift-content'\nexport * from './work-shift/work-shift-baseline'\n/*\n * This file names each source file rather than re-exporting the folder barrel, so anything added\n * to that barrel stops at the package boundary unless it is also listed here. `daysOfWeek` is\n * stored as a CSV and every consumer has to parse it, so the parser has to be reachable — a\n * consumer that cannot import it writes its own, and the two disagree quietly.\n */\nexport * from './work-shift/days-of-week'\n\n/* IMPORT ENTITIES AND RESOLVERS */\nimport { entities as WorkShiftEntities, resolvers as WorkShiftResolvers } from './work-shift'\n\nexport const entities = [ \n /* ENTITIES */\n\t...WorkShiftEntities,\n] \n\n\nexport const schema = {\n resolverClasses: [\n /* RESOLVER CLASSES */\n\t\t...WorkShiftResolvers,\n ] \n}\n"]}
|
|
@@ -4,5 +4,5 @@ import { WorkShiftMutation } from './work-shift-mutation';
|
|
|
4
4
|
import { WorkShiftLifecycleResolver } from './work-shift-lifecycle-resolver';
|
|
5
5
|
import { WorkShiftArrangement } from './work-shift-arrangement';
|
|
6
6
|
export * from './days-of-week';
|
|
7
|
-
export declare const entities: (typeof
|
|
7
|
+
export declare const entities: (typeof WorkShift | typeof import("./work-shift-revision").WorkShiftRevision | typeof import("./work-shift-revision").WorkShiftPlan | typeof import("./work-shift-revision").WorkShiftSegment | typeof import("./work-shift-revision").WorkShiftBasis | typeof WorkShiftArrangement)[];
|
|
8
8
|
export declare const resolvers: (typeof DomainWorkShiftQuery | typeof WorkShiftQuery | typeof WorkShiftMutation | typeof WorkShiftLifecycleResolver)[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DataSource } from 'typeorm';
|
|
2
|
+
import { Domain } from '@things-factory/shell';
|
|
3
|
+
/**
|
|
4
|
+
* 판을 올린 설치본의 교대에 첫 편성 개정본을 세운다 — 기준선(2026-09-24). 규칙은 ops-master 의
|
|
5
|
+
* `revision-baseline` 과 같다. 편성은 이 꾸러미의 것이라 여기서 세운다 — ops-master 는 이 꾸러미를 모른다.
|
|
6
|
+
*
|
|
7
|
+
* 사업장마다 트랜잭션 하나. 하나가 실패해도 나머지는 선다. 실패한 사업장을 크게 말하고, 던지지 않는다.
|
|
8
|
+
*/
|
|
9
|
+
export interface WorkShiftBaselineReport {
|
|
10
|
+
domain: string;
|
|
11
|
+
stood: number;
|
|
12
|
+
unreadable: {
|
|
13
|
+
name: string;
|
|
14
|
+
problem: string;
|
|
15
|
+
}[];
|
|
16
|
+
failed?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function workShiftBaselineEdition(): string;
|
|
19
|
+
export declare function standWorkShiftBaselines(dataSource: DataSource, options?: {
|
|
20
|
+
edition?: string;
|
|
21
|
+
domains?: Domain[];
|
|
22
|
+
}): Promise<WorkShiftBaselineReport[]>;
|
|
23
|
+
export declare function standWorkShiftBaselinesAtBoot(dataSource: DataSource): Promise<WorkShiftBaselineReport[]>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.workShiftBaselineEdition = workShiftBaselineEdition;
|
|
4
|
+
exports.standWorkShiftBaselines = standWorkShiftBaselines;
|
|
5
|
+
exports.standWorkShiftBaselinesAtBoot = standWorkShiftBaselinesAtBoot;
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
|
+
const work_shift_lifecycle_1 = require("./work-shift-lifecycle");
|
|
8
|
+
function workShiftBaselineEdition() {
|
|
9
|
+
try {
|
|
10
|
+
return `@things-factory/work-shift ${require('../../../package.json').version}`;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return '@things-factory/work-shift';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function standWorkShiftBaselines(dataSource, options = {}) {
|
|
17
|
+
const edition = options.edition ?? workShiftBaselineEdition();
|
|
18
|
+
const domains = options.domains ?? (await dataSource.getRepository(shell_1.Domain).find());
|
|
19
|
+
const reports = [];
|
|
20
|
+
for (const domain of domains) {
|
|
21
|
+
const at = new Date();
|
|
22
|
+
try {
|
|
23
|
+
const outcome = await dataSource.transaction(manager => (0, work_shift_lifecycle_1.standWorkShiftBaseline)(manager, domain.id, at, edition));
|
|
24
|
+
reports.push({ domain: domain.name, ...outcome });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
reports.push({ domain: domain.name, stood: 0, unreadable: [], failed: error?.code ?? error?.message ?? String(error) });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return reports;
|
|
31
|
+
}
|
|
32
|
+
async function standWorkShiftBaselinesAtBoot(dataSource) {
|
|
33
|
+
let reports;
|
|
34
|
+
try {
|
|
35
|
+
reports = await standWorkShiftBaselines(dataSource);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`[work-shift] 교대 기준선을 세우지 못했습니다 — 사업장을 읽지 못함: ${error?.message ?? error}`);
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
for (const report of reports) {
|
|
42
|
+
if (report.failed) {
|
|
43
|
+
console.error(`[work-shift] ⚠ 교대 기준선을 세우지 못했습니다 — ${report.domain}: ${report.failed}. 이 사업장의 실적은 교대 없이 적힙니다.`);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (report.stood)
|
|
47
|
+
console.info(`[work-shift] 교대 기준선 ${report.domain}: 지금의 교대를 첫 편성 개정본으로 세웠습니다`);
|
|
48
|
+
for (const one of report.unreadable) {
|
|
49
|
+
console.warn(`[work-shift] ⚠ 교대 기준선을 못 세웠습니다 — ${report.domain} · ${one.name}: ${one.problem}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return reports;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=work-shift-baseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-shift-baseline.js","sourceRoot":"","sources":["../../../server/service/work-shift/work-shift-baseline.ts"],"names":[],"mappings":";;AAkBA,4DAMC;AAED,0DAiBC;AAED,sEAmBC;AA/DD,iDAA8C;AAE9C,iEAA+D;AAe/D,SAAgB,wBAAwB;IACtC,IAAI,CAAC;QACH,OAAO,8BAA8B,OAAO,CAAC,uBAAuB,CAAC,CAAC,OAAO,EAAE,CAAA;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,4BAA4B,CAAA;IACrC,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,uBAAuB,CAC3C,UAAsB,EACtB,UAAoD,EAAE;IAEtD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,wBAAwB,EAAE,CAAA;IAC7D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,MAAM,UAAU,CAAC,aAAa,CAAC,cAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IAClF,MAAM,OAAO,GAA8B,EAAE,CAAA;IAC7C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAA;QACrB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,IAAA,6CAAsB,EAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAA;YAChH,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC,CAAA;QACnD,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACzH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAEM,KAAK,UAAU,6BAA6B,CAAC,UAAsB;IACxE,IAAI,OAAkC,CAAA;IACtC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,uBAAuB,CAAC,UAAU,CAAC,CAAA;IACrD,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,gDAAgD,KAAK,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC,CAAA;QACxF,OAAO,EAAE,CAAA;IACX,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,sCAAsC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,0BAA0B,CAAC,CAAA;YAC9G,SAAQ;QACV,CAAC;QACD,IAAI,MAAM,CAAC,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,uBAAuB,MAAM,CAAC,MAAM,4BAA4B,CAAC,CAAA;QAChG,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,oCAAoC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;QACjG,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC","sourcesContent":["import { DataSource } from 'typeorm'\nimport { Domain } from '@things-factory/shell'\n\nimport { standWorkShiftBaseline } from './work-shift-lifecycle'\n\n/**\n * 판을 올린 설치본의 교대에 첫 편성 개정본을 세운다 — 기준선(2026-09-24). 규칙은 ops-master 의\n * `revision-baseline` 과 같다. 편성은 이 꾸러미의 것이라 여기서 세운다 — ops-master 는 이 꾸러미를 모른다.\n *\n * 사업장마다 트랜잭션 하나. 하나가 실패해도 나머지는 선다. 실패한 사업장을 크게 말하고, 던지지 않는다.\n */\nexport interface WorkShiftBaselineReport {\n domain: string\n stood: number\n unreadable: { name: string; problem: string }[]\n failed?: string\n}\n\nexport function workShiftBaselineEdition(): string {\n try {\n return `@things-factory/work-shift ${require('../../../package.json').version}`\n } catch {\n return '@things-factory/work-shift'\n }\n}\n\nexport async function standWorkShiftBaselines(\n dataSource: DataSource,\n options: { edition?: string; domains?: Domain[] } = {}\n): Promise<WorkShiftBaselineReport[]> {\n const edition = options.edition ?? workShiftBaselineEdition()\n const domains = options.domains ?? (await dataSource.getRepository(Domain).find())\n const reports: WorkShiftBaselineReport[] = []\n for (const domain of domains) {\n const at = new Date()\n try {\n const outcome = await dataSource.transaction(manager => standWorkShiftBaseline(manager, domain.id, at, edition))\n reports.push({ domain: domain.name, ...outcome })\n } catch (error: any) {\n reports.push({ domain: domain.name, stood: 0, unreadable: [], failed: error?.code ?? error?.message ?? String(error) })\n }\n }\n return reports\n}\n\nexport async function standWorkShiftBaselinesAtBoot(dataSource: DataSource) {\n let reports: WorkShiftBaselineReport[]\n try {\n reports = await standWorkShiftBaselines(dataSource)\n } catch (error: any) {\n console.error(`[work-shift] 교대 기준선을 세우지 못했습니다 — 사업장을 읽지 못함: ${error?.message ?? error}`)\n return []\n }\n for (const report of reports) {\n if (report.failed) {\n console.error(`[work-shift] ⚠ 교대 기준선을 세우지 못했습니다 — ${report.domain}: ${report.failed}. 이 사업장의 실적은 교대 없이 적힙니다.`)\n continue\n }\n if (report.stood) console.info(`[work-shift] 교대 기준선 ${report.domain}: 지금의 교대를 첫 편성 개정본으로 세웠습니다`)\n for (const one of report.unreadable) {\n console.warn(`[work-shift] ⚠ 교대 기준선을 못 세웠습니다 — ${report.domain} · ${one.name}: ${one.problem}`)\n }\n }\n return reports\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WorkShift } from './work-shift';
|
|
1
2
|
export interface ShiftDefinition {
|
|
2
3
|
name: string;
|
|
3
4
|
description?: string;
|
|
@@ -13,3 +14,5 @@ export declare function shiftDraftContent(input: any, stored?: boolean): {
|
|
|
13
14
|
timezone: string;
|
|
14
15
|
shifts: ShiftDefinition[];
|
|
15
16
|
};
|
|
17
|
+
/** Every field affecting execution belongs to the signed arrangement. */
|
|
18
|
+
export declare function shiftSetOf(shifts: Partial<WorkShift>[]): Record<string, unknown>[];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.shiftDraftContent = shiftDraftContent;
|
|
4
|
+
exports.shiftSetOf = shiftSetOf;
|
|
4
5
|
const tslib_1 = require("tslib");
|
|
5
6
|
const moment_timezone_1 = tslib_1.__importDefault(require("moment-timezone"));
|
|
6
7
|
const shell_1 = require("@things-factory/shell");
|
|
@@ -52,4 +53,10 @@ function shiftDraftContent(input, stored = false) {
|
|
|
52
53
|
invalid('Arrangement description must be text.');
|
|
53
54
|
return { description: input.description ?? null, timezone: input.timezone, shifts };
|
|
54
55
|
}
|
|
56
|
+
/** Every field affecting execution belongs to the signed arrangement. */
|
|
57
|
+
function shiftSetOf(shifts) {
|
|
58
|
+
return shifts.map(s => ({ name: s.name, description: s.description ?? '', fromDate: s.fromDate,
|
|
59
|
+
fromTime: s.fromTime, toDate: s.toDate, toTime: s.toTime, daysOfWeek: s.daysOfWeek ?? '' }))
|
|
60
|
+
.sort((a, b) => a.fromDate - b.fromDate || a.fromTime.localeCompare(b.fromTime));
|
|
61
|
+
}
|
|
55
62
|
//# sourceMappingURL=work-shift-content.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-shift-content.js","sourceRoot":"","sources":["../../../server/service/work-shift/work-shift-content.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"work-shift-content.js","sourceRoot":"","sources":["../../../server/service/work-shift/work-shift-content.ts"],"names":[],"mappings":"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","sourcesContent":["import moment from 'moment-timezone'\nimport { Refusal } from '@things-factory/shell'\nimport type { WorkShift } from './work-shift'\n\nexport interface ShiftDefinition {\n name: string\n description?: string\n fromDate: number\n fromTime: string\n toDate: number\n toTime: string\n daysOfWeek: string\n}\nfunction invalid(detail: string): never { throw new Refusal('INVALID_SHIFT_CONTENT', {}, detail) }\nconst clock = (value: unknown) => {\n if (typeof value !== 'string' || !/^([01]\\d|2[0-3]):[0-5]\\d(:00)?$/.test(value)) invalid('Use HH:mm with minute precision.')\n return String(value).slice(0, 5)\n}\nconst minutes = (value: string) => Number(value.slice(0, 2)) * 60 + Number(value.slice(3))\n\n/** Weekdays refer to the work date, including shifts starting the previous/next day. */\nexport function shiftDraftContent(input: any, stored = false) {\n if (!input || typeof input !== 'object' || (!stored && Object.keys(input).some(k => !['description','timezone','shifts','effectiveFrom','reason'].includes(k)))) invalid('Unexpected shift arrangement fields.')\n if (typeof input.timezone !== 'string' || !moment.tz.zone(input.timezone)) invalid('Choose an IANA time zone.')\n if (!Array.isArray(input.shifts) || !input.shifts.length || input.shifts.length > 64) invalid('Provide between 1 and 64 shifts.')\n const names = new Set<string>(), windows: { from: number; to: number; name: string }[] = []\n const shifts: ShiftDefinition[] = input.shifts.map((row: any) => {\n if (!row || Object.keys(row).some(k => !['name','description','fromDate','fromTime','toDate','toTime','daysOfWeek'].includes(k))) invalid('Unexpected shift fields.')\n const name = typeof row.name === 'string' ? row.name.trim() : ''\n if (!name || name.length > 128 || names.has(name)) invalid('Shift names must be nonempty and unique within the arrangement.')\n names.add(name)\n if (![-1,0,1].includes(row.fromDate) || ![-1,0,1].includes(row.toDate)) invalid('Date offsets must be -1, 0 or 1.')\n const fromTime = clock(row.fromTime), toTime = clock(row.toTime)\n const from = row.fromDate * 1440 + minutes(fromTime), to = row.toDate * 1440 + minutes(toTime)\n if (to <= from || to - from > 1440) invalid('A shift must end after it starts and last at most 24 hours.')\n const said = row.daysOfWeek ?? ''\n if (typeof said !== 'string' || (said !== '' && !/^[0-6](,[0-6])*$/.test(said))) invalid('Weekdays must be a list of 0 (Sunday) through 6 (Saturday).')\n const days = said === '' ? [0,1,2,3,4,5,6] : [...new Set(said.split(',').map(Number))].sort()\n for (const day of days) for (const week of [-1,0,1]) windows.push({ from: from + day * 1440 + week * 10080, to: to + day * 1440 + week * 10080, name })\n if (row.description != null && typeof row.description !== 'string') invalid('Shift description must be text.')\n return { name, description: row.description ?? '', fromDate: row.fromDate, fromTime, toDate: row.toDate, toTime, daysOfWeek: days.length === 7 ? '' : days.join(',') }\n }).sort((a: ShiftDefinition,b: ShiftDefinition) => a.fromDate - b.fromDate || a.fromTime.localeCompare(b.fromTime) || a.name.localeCompare(b.name))\n windows.sort((a,b) => a.from - b.from)\n for (let i = 1; i < windows.length; i++) if (windows[i].from < windows[i-1].to) invalid(`Shifts overlap: ${windows[i-1].name}, ${windows[i].name}.`)\n if (input.description != null && typeof input.description !== 'string') invalid('Arrangement description must be text.')\n return { description: input.description ?? null, timezone: input.timezone as string, shifts }\n}\n\n/** Every field affecting execution belongs to the signed arrangement. */\nexport function shiftSetOf(shifts: Partial<WorkShift>[]): Record<string, unknown>[] {\n return shifts.map(s => ({ name: s.name, description: s.description ?? '', fromDate: s.fromDate,\n fromTime: s.fromTime, toDate: s.toDate, toTime: s.toTime, daysOfWeek: s.daysOfWeek ?? '' }))\n .sort((a,b) => a.fromDate - b.fromDate || a.fromTime.localeCompare(b.fromTime))\n}\n"]}
|
|
@@ -3,6 +3,7 @@ export declare class WorkShiftLifecycleResolver {
|
|
|
3
3
|
workShiftRevisionOverview(context: ResolverContext): Promise<{
|
|
4
4
|
approvalRequired: boolean;
|
|
5
5
|
timezone: string;
|
|
6
|
+
legacyShifts?: Record<string, unknown>[];
|
|
6
7
|
arrangementId: string;
|
|
7
8
|
name: string;
|
|
8
9
|
generation: number;
|
|
@@ -40,8 +41,8 @@ export declare class WorkShiftLifecycleResolver {
|
|
|
40
41
|
shifts: import("./work-shift-content").ShiftDefinition[];
|
|
41
42
|
effectiveFrom: Date;
|
|
42
43
|
reason: string;
|
|
43
|
-
creator: import("@things-factory/auth-base").User;
|
|
44
|
-
creatorId: string;
|
|
44
|
+
creator: import("@things-factory/auth-base").User | null;
|
|
45
|
+
creatorId: string | null;
|
|
45
46
|
createdAt: Date;
|
|
46
47
|
frozenAt: Date | null;
|
|
47
48
|
contentHash: string | null;
|
|
@@ -50,6 +51,7 @@ export declare class WorkShiftLifecycleResolver {
|
|
|
50
51
|
} | {
|
|
51
52
|
approvalRequired: boolean;
|
|
52
53
|
timezone: string;
|
|
54
|
+
legacyShifts?: Record<string, unknown>[];
|
|
53
55
|
revisions: any[];
|
|
54
56
|
schedule: any[];
|
|
55
57
|
generation: number;
|
|
@@ -57,4 +59,9 @@ export declare class WorkShiftLifecycleResolver {
|
|
|
57
59
|
createWorkShiftDraft(content: any, context: ResolverContext): Promise<import("./work-shift-revision").WorkShiftRevision>;
|
|
58
60
|
editWorkShiftDraft(id: string, generation: number, content: any, context: ResolverContext): Promise<import("./work-shift-revision").WorkShiftRevision>;
|
|
59
61
|
publishWorkShiftDraft(id: string, generation: number, context: ResolverContext): Promise<import("./work-shift-revision").WorkShiftPlan>;
|
|
62
|
+
/** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */
|
|
63
|
+
saveAndPublishWorkShift(content: any, context: ResolverContext): Promise<{
|
|
64
|
+
revision: import("./work-shift-revision").WorkShiftRevision;
|
|
65
|
+
plan: import("./work-shift-revision").WorkShiftPlan;
|
|
66
|
+
}>;
|
|
60
67
|
}
|
|
@@ -4,16 +4,11 @@ exports.WorkShiftLifecycleResolver = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const shell_1 = require("@things-factory/shell");
|
|
7
|
-
const ops_master_1 = require("@things-factory/ops-master");
|
|
8
7
|
const work_shift_arrangement_1 = require("./work-shift-arrangement");
|
|
9
8
|
const work_shift_lifecycle_1 = require("./work-shift-lifecycle");
|
|
10
9
|
let WorkShiftLifecycleResolver = class WorkShiftLifecycleResolver {
|
|
11
10
|
async workShiftRevisionOverview(context) {
|
|
12
|
-
|
|
13
|
-
const policy = await (0, ops_master_1.masterChangePolicy)(manager, domain.id, 'workShift');
|
|
14
|
-
const root = await manager.findOneBy(work_shift_arrangement_1.WorkShiftArrangement, { domain: { id: domain.id } });
|
|
15
|
-
return { ...(root ? await (0, work_shift_lifecycle_1.workShiftRevisionOverview)(manager, domain.id, root.id) : { revisions: [], schedule: [], generation: 0 }),
|
|
16
|
-
approvalRequired: policy.approvalRequired, timezone: domain.timezone || 'UTC' };
|
|
11
|
+
return (0, work_shift_lifecycle_1.workShiftOverviewFor)((0, shell_1.getRepository)(work_shift_arrangement_1.WorkShiftArrangement).manager, context.state.domain);
|
|
17
12
|
}
|
|
18
13
|
async createWorkShiftDraft(content, context) {
|
|
19
14
|
const { tx, domain, user } = context.state;
|
|
@@ -27,6 +22,11 @@ let WorkShiftLifecycleResolver = class WorkShiftLifecycleResolver {
|
|
|
27
22
|
const { tx, domain, user } = context.state;
|
|
28
23
|
return (0, work_shift_lifecycle_1.publishUnregulatedWorkShift)(tx, domain.id, user.id, id, generation);
|
|
29
24
|
}
|
|
25
|
+
/** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */
|
|
26
|
+
async saveAndPublishWorkShift(content, context) {
|
|
27
|
+
const { tx, domain, user } = context.state;
|
|
28
|
+
return (0, work_shift_lifecycle_1.saveAndPublishWorkShift)(tx, domain.id, user.id, { content });
|
|
29
|
+
}
|
|
30
30
|
};
|
|
31
31
|
exports.WorkShiftLifecycleResolver = WorkShiftLifecycleResolver;
|
|
32
32
|
tslib_1.__decorate([
|
|
@@ -70,6 +70,16 @@ tslib_1.__decorate([
|
|
|
70
70
|
tslib_1.__metadata("design:paramtypes", [String, Number, Object]),
|
|
71
71
|
tslib_1.__metadata("design:returntype", Promise)
|
|
72
72
|
], WorkShiftLifecycleResolver.prototype, "publishWorkShiftDraft", null);
|
|
73
|
+
tslib_1.__decorate([
|
|
74
|
+
(0, type_graphql_1.Directive)('@privilege(category: "work-shift", privilege: "mutation", domainOwnerGranted: true)'),
|
|
75
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
76
|
+
(0, type_graphql_1.Mutation)(() => shell_1.ScalarObject),
|
|
77
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('content', () => shell_1.ScalarObject)),
|
|
78
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
79
|
+
tslib_1.__metadata("design:type", Function),
|
|
80
|
+
tslib_1.__metadata("design:paramtypes", [Object, Object]),
|
|
81
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
82
|
+
], WorkShiftLifecycleResolver.prototype, "saveAndPublishWorkShift", null);
|
|
73
83
|
exports.WorkShiftLifecycleResolver = WorkShiftLifecycleResolver = tslib_1.__decorate([
|
|
74
84
|
(0, type_graphql_1.Resolver)(),
|
|
75
85
|
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-shift-lifecycle-resolver.js","sourceRoot":"","sources":["../../../server/service/work-shift/work-shift-lifecycle-resolver.ts"],"names":[],"mappings":";;;;AAAA,+CAAiG;AACjG,iDAAkF;AAClF,
|
|
1
|
+
{"version":3,"file":"work-shift-lifecycle-resolver.js","sourceRoot":"","sources":["../../../server/service/work-shift/work-shift-lifecycle-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Int, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql'\nimport { getRepository, ScalarObject, SpeakRefusals } from '@things-factory/shell'\nimport { WorkShiftArrangement } from './work-shift-arrangement'\nimport { createWorkShiftDraft, editWorkShiftDraft, publishUnregulatedWorkShift, saveAndPublishWorkShift, workShiftOverviewFor } from './work-shift-lifecycle'\n\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class WorkShiftLifecycleResolver {\n @Directive('@privilege(category: \"work-shift\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(() => ScalarObject)\n async workShiftRevisionOverview(@Ctx() context: ResolverContext) {\n return workShiftOverviewFor(getRepository(WorkShiftArrangement).manager, context.state.domain)\n }\n @Directive('@privilege(category: \"work-shift\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async createWorkShiftDraft(@Arg('content', () => ScalarObject) content: any, @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return createWorkShiftDraft(tx, domain.id, user.id, { content })\n }\n @Directive('@privilege(category: \"work-shift\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async editWorkShiftDraft(@Arg('revisionId') id: string, @Arg('editGeneration', () => Int) generation: number,\n @Arg('content', () => ScalarObject) content: any, @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return editWorkShiftDraft(tx, domain.id, user.id, id, generation, content)\n }\n @Directive('@privilege(category: \"work-shift\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async publishWorkShiftDraft(@Arg('revisionId') id: string, @Arg('editGeneration', () => Int) generation: number, @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return publishUnregulatedWorkShift(tx, domain.id, user.id, id, generation)\n }\n\n /** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */\n @Directive('@privilege(category: \"work-shift\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async saveAndPublishWorkShift(@Arg('content', () => ScalarObject) content: any, @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return saveAndPublishWorkShift(tx, domain.id, user.id, { content })\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EntityManager } from 'typeorm';
|
|
2
|
-
import { Refusal } from '@things-factory/shell';
|
|
2
|
+
import { Domain, Refusal } from '@things-factory/shell';
|
|
3
3
|
import { WorkShiftArrangement } from './work-shift-arrangement';
|
|
4
4
|
import { WorkShiftBasis, WorkShiftPlan, WorkShiftRevision, WorkShiftSegment } from './work-shift-revision';
|
|
5
5
|
export declare class WorkShiftRefusal extends Refusal {
|
|
@@ -78,6 +78,24 @@ export declare function resolveWorkShift(manager: EntityManager, domainId: strin
|
|
|
78
78
|
plan: WorkShiftPlan;
|
|
79
79
|
segment: WorkShiftSegment;
|
|
80
80
|
}>;
|
|
81
|
+
/**
|
|
82
|
+
* **편성 개정본이 하나도 없는 사업장**에 지금 서 있는 교대 행들을 첫 개정본으로 적는다 — 기준선
|
|
83
|
+
* (2026-09-24, ops-master `standMasterBaselines` 와 같은 판정). 개정 체계 전부터 있던 교대(`work_shifts`)는
|
|
84
|
+
* 편성으로 한 번도 올라간 적이 없어서, 교대 조회가 빈 목록을 답하고 실적이 교대 없이 적혔다.
|
|
85
|
+
*
|
|
86
|
+
* - 교대 행 전부가 한 벌이다(편성은 사업장마다 하나). 값은 행 그대로, 시간대는 사업장의 것이다.
|
|
87
|
+
* 사업장에 시간대가 없거나 그 벌이 편성 검사를 못 지나면 세우지 않고 까닭을 말한다 — 지어내지 않는다.
|
|
88
|
+
* - 결재 없음 · 발행 종류 `baseline` · 작성자와 발행자는 비고 판이 사유에 남는다. 유효 시작은 세운 시각.
|
|
89
|
+
* - 편성 개정본이 하나라도 있으면 손대지 않는다. 둘이 동시에 돌면 편성의 도메인 유니크 · 개정 번호
|
|
90
|
+
* 유니크 · 세대 조건부 갱신이 둘째를 물린다.
|
|
91
|
+
*/
|
|
92
|
+
export declare function standWorkShiftBaseline(manager: EntityManager, domainId: string, at: Date, edition: string): Promise<{
|
|
93
|
+
stood: number;
|
|
94
|
+
unreadable: {
|
|
95
|
+
name: string;
|
|
96
|
+
problem: string;
|
|
97
|
+
}[];
|
|
98
|
+
}>;
|
|
81
99
|
/** Replay reads verify the captured digest too, not only the currently effective schedule. */
|
|
82
100
|
export declare function workShiftRevisionForBasis(manager: EntityManager, domainId: string, basis: WorkShiftBasis): Promise<WorkShiftRevision>;
|
|
83
101
|
/** Must run inside the transaction that writes the business record. */
|
|
@@ -90,7 +108,61 @@ export declare function workShiftRevisionOverview(manager: EntityManager, domain
|
|
|
90
108
|
schedule: {
|
|
91
109
|
state: string;
|
|
92
110
|
id: string;
|
|
93
|
-
domain:
|
|
111
|
+
domain: Domain;
|
|
112
|
+
domainId: string;
|
|
113
|
+
arrangement: WorkShiftArrangement;
|
|
114
|
+
arrangementId: string;
|
|
115
|
+
plan: WorkShiftPlan;
|
|
116
|
+
planId: string;
|
|
117
|
+
revision: WorkShiftRevision;
|
|
118
|
+
revisionId: string;
|
|
119
|
+
validFrom: Date;
|
|
120
|
+
validTo: Date | null;
|
|
121
|
+
}[];
|
|
122
|
+
revisions: {
|
|
123
|
+
state: string;
|
|
124
|
+
revisionNumber: number;
|
|
125
|
+
policy: import("@things-factory/ops-master").MasterChangePolicy;
|
|
126
|
+
policyId: string;
|
|
127
|
+
id: string;
|
|
128
|
+
domain: Domain;
|
|
129
|
+
domainId: string;
|
|
130
|
+
arrangement: WorkShiftArrangement;
|
|
131
|
+
arrangementId: string;
|
|
132
|
+
baseRevision: WorkShiftRevision | null;
|
|
133
|
+
baseRevisionId: string | null;
|
|
134
|
+
baseGeneration: number;
|
|
135
|
+
editGeneration: number;
|
|
136
|
+
description: string | null;
|
|
137
|
+
timezone: string;
|
|
138
|
+
shifts: import("./work-shift-content").ShiftDefinition[];
|
|
139
|
+
effectiveFrom: Date;
|
|
140
|
+
reason: string;
|
|
141
|
+
creator: import("@things-factory/auth-base").User | null;
|
|
142
|
+
creatorId: string | null;
|
|
143
|
+
createdAt: Date;
|
|
144
|
+
frozenAt: Date | null;
|
|
145
|
+
contentHash: string | null;
|
|
146
|
+
activityInstanceId: string | null;
|
|
147
|
+
}[];
|
|
148
|
+
}>;
|
|
149
|
+
/**
|
|
150
|
+
* 교대 화면이 여는 것. **읽기만 한다** — 정책 줄이 없으면 기본값으로 답하고 줄을 세우지 않는다(2026-09-24).
|
|
151
|
+
* 앞서는 `masterChangePolicy` 로 줄을 세우려다 트랜잭션 밖이라 거절했고, 정책 줄이 없는 사업장은 화면이 안
|
|
152
|
+
* 열렸다. 기준선이 못 선 사업장은 줄이 끝내 안 생기므로 그 사업장을 고칠 화면이 영영 안 열렸다.
|
|
153
|
+
*/
|
|
154
|
+
export declare function workShiftOverviewFor(manager: EntityManager, domain: Domain): Promise<{
|
|
155
|
+
approvalRequired: boolean;
|
|
156
|
+
timezone: string;
|
|
157
|
+
legacyShifts?: Record<string, unknown>[];
|
|
158
|
+
arrangementId: string;
|
|
159
|
+
name: string;
|
|
160
|
+
generation: number;
|
|
161
|
+
at: string;
|
|
162
|
+
schedule: {
|
|
163
|
+
state: string;
|
|
164
|
+
id: string;
|
|
165
|
+
domain: Domain;
|
|
94
166
|
domainId: string;
|
|
95
167
|
arrangement: WorkShiftArrangement;
|
|
96
168
|
arrangementId: string;
|
|
@@ -107,7 +179,7 @@ export declare function workShiftRevisionOverview(manager: EntityManager, domain
|
|
|
107
179
|
policy: import("@things-factory/ops-master").MasterChangePolicy;
|
|
108
180
|
policyId: string;
|
|
109
181
|
id: string;
|
|
110
|
-
domain:
|
|
182
|
+
domain: Domain;
|
|
111
183
|
domainId: string;
|
|
112
184
|
arrangement: WorkShiftArrangement;
|
|
113
185
|
arrangementId: string;
|
|
@@ -120,11 +192,32 @@ export declare function workShiftRevisionOverview(manager: EntityManager, domain
|
|
|
120
192
|
shifts: import("./work-shift-content").ShiftDefinition[];
|
|
121
193
|
effectiveFrom: Date;
|
|
122
194
|
reason: string;
|
|
123
|
-
creator: import("@things-factory/auth-base").User;
|
|
124
|
-
creatorId: string;
|
|
195
|
+
creator: import("@things-factory/auth-base").User | null;
|
|
196
|
+
creatorId: string | null;
|
|
125
197
|
createdAt: Date;
|
|
126
198
|
frozenAt: Date | null;
|
|
127
199
|
contentHash: string | null;
|
|
128
200
|
activityInstanceId: string | null;
|
|
129
201
|
}[];
|
|
202
|
+
} | {
|
|
203
|
+
approvalRequired: boolean;
|
|
204
|
+
timezone: string;
|
|
205
|
+
legacyShifts?: Record<string, unknown>[];
|
|
206
|
+
revisions: any[];
|
|
207
|
+
schedule: any[];
|
|
208
|
+
generation: number;
|
|
209
|
+
}>;
|
|
210
|
+
/**
|
|
211
|
+
* **비규제 사업장의 「저장」 한 번** — 초안을 만들고 바로 발행한다, 한 트랜잭션에서(ADR-0086 09-22 보탬).
|
|
212
|
+
* 비규제면 사람이 누를 것은 저장 하나다. 두 걸음(초안 저장 → 발행)이 구조상 필연인 것처럼 보이게 하지 않는다.
|
|
213
|
+
* 이 축이 승인제면 발행이 `MASTER_APPROVAL_REQUIRED` 로 거절되고, 같은 트랜잭션이라 초안도 함께 물러난다 —
|
|
214
|
+
* 반쯤 저장된 것이 남지 않는다. 개정본 · 적용계획 · 구간은 두 걸음 때와 똑같이 선다.
|
|
215
|
+
*/
|
|
216
|
+
export declare function saveAndPublishWorkShift(manager: EntityManager, domainId: string, actorId: string, asked: {
|
|
217
|
+
arrangementId?: string;
|
|
218
|
+
baseRevisionId?: string;
|
|
219
|
+
content: WorkShiftDraftContent;
|
|
220
|
+
}): Promise<{
|
|
221
|
+
revision: WorkShiftRevision;
|
|
222
|
+
plan: WorkShiftPlan;
|
|
130
223
|
}>;
|