@things-factory/work-shift 10.1.33 → 10.1.35

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.
Files changed (51) hide show
  1. package/dist-client/pages/work-shift.d.ts +18 -102
  2. package/dist-client/pages/work-shift.js +165 -781
  3. package/dist-client/pages/work-shift.js.map +1 -1
  4. package/dist-client/tsconfig.tsbuildinfo +1 -1
  5. package/dist-server/controllers/work-shift-range.d.ts +25 -9
  6. package/dist-server/controllers/work-shift-range.js +49 -196
  7. package/dist-server/controllers/work-shift-range.js.map +1 -1
  8. package/dist-server/controllers/work-shift-schedule.d.ts +2 -0
  9. package/dist-server/controllers/work-shift-schedule.js +9 -18
  10. package/dist-server/controllers/work-shift-schedule.js.map +1 -1
  11. package/dist-server/service/index.d.ts +5 -2
  12. package/dist-server/service/index.js +3 -0
  13. package/dist-server/service/index.js.map +1 -1
  14. package/dist-server/service/work-shift/index.d.ts +4 -4
  15. package/dist-server/service/work-shift/index.js +4 -3
  16. package/dist-server/service/work-shift/index.js.map +1 -1
  17. package/dist-server/service/work-shift/shift-occurrence.d.ts +19 -0
  18. package/dist-server/service/work-shift/shift-occurrence.js +34 -0
  19. package/dist-server/service/work-shift/shift-occurrence.js.map +1 -0
  20. package/dist-server/service/work-shift/work-shift-arrangement.d.ts +10 -0
  21. package/dist-server/service/work-shift/work-shift-arrangement.js +40 -0
  22. package/dist-server/service/work-shift/work-shift-arrangement.js.map +1 -0
  23. package/dist-server/service/work-shift/work-shift-content.d.ts +15 -0
  24. package/dist-server/service/work-shift/work-shift-content.js +55 -0
  25. package/dist-server/service/work-shift/work-shift-content.js.map +1 -0
  26. package/dist-server/service/work-shift/work-shift-lifecycle-resolver.d.ts +60 -0
  27. package/dist-server/service/work-shift/work-shift-lifecycle-resolver.js +77 -0
  28. package/dist-server/service/work-shift/work-shift-lifecycle-resolver.js.map +1 -0
  29. package/dist-server/service/work-shift/work-shift-lifecycle.d.ts +130 -0
  30. package/dist-server/service/work-shift/work-shift-lifecycle.js +508 -0
  31. package/dist-server/service/work-shift/work-shift-lifecycle.js.map +1 -0
  32. package/dist-server/service/work-shift/work-shift-mutation.js +9 -42
  33. package/dist-server/service/work-shift/work-shift-mutation.js.map +1 -1
  34. package/dist-server/service/work-shift/work-shift-query.js +30 -15
  35. package/dist-server/service/work-shift/work-shift-query.js.map +1 -1
  36. package/dist-server/service/work-shift/work-shift-revision-service.d.ts +29 -65
  37. package/dist-server/service/work-shift/work-shift-revision-service.js +67 -167
  38. package/dist-server/service/work-shift/work-shift-revision-service.js.map +1 -1
  39. package/dist-server/service/work-shift/work-shift-revision.d.ts +78 -62
  40. package/dist-server/service/work-shift/work-shift-revision.js +303 -82
  41. package/dist-server/service/work-shift/work-shift-revision.js.map +1 -1
  42. package/dist-server/service/work-shift/work-shift-type.d.ts +0 -5
  43. package/dist-server/service/work-shift/work-shift-type.js +1 -16
  44. package/dist-server/service/work-shift/work-shift-type.js.map +1 -1
  45. package/dist-server/tsconfig.tsbuildinfo +1 -1
  46. package/helps/page/work-shift.ko.md +19 -3
  47. package/helps/page/work-shift.md +17 -9
  48. package/package.json +8 -5
  49. package/dist-server/service/work-shift/work-shift-revision-query.d.ts +0 -20
  50. package/dist-server/service/work-shift/work-shift-revision-query.js +0 -74
  51. package/dist-server/service/work-shift/work-shift-revision-query.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"work-shift-revision-service.js","sourceRoot":"","sources":["../../../server/service/work-shift/work-shift-revision-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, IsNull } from 'typeorm'\n\nimport { Domain } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\nimport { WorkShift } from './work-shift'\nimport { WorkShiftRevision } from './work-shift-revision'\nimport { RevisionLike, SetOrigin, announcedSets, selectSetAt } from './work-shift-selection'\n\n/**\n * 편성이 바뀔 때 지나간 것을 남기고, 지난 시각의 편성을 되찾는다.\n */\n\n/** 편성 한 벌에서 남길 것만 뽑는다. id·감사 칸은 지워진 행의 것이라 되살려도 쓸 데가 없다. */\nexport function shiftSetOf(shifts: WorkShift[]): Record<string, unknown>[] {\n return shifts\n .map(shift => ({\n name: shift.name,\n fromDate: shift.fromDate,\n fromTime: shift.fromTime,\n toDate: shift.toDate,\n toTime: shift.toTime\n }))\n .sort((a, b) => a.fromDate - b.fromDate || String(a.fromTime).localeCompare(String(b.fromTime)))\n}\n\n/** 두 편성이 같은가. 같으면 남기지 않는다 — 바뀌지 않은 저장으로 이력이 늘면 읽을 수 없게 된다. */\nexport function sameShiftSet(before: Record<string, unknown>[], after: Record<string, unknown>[]): boolean {\n return JSON.stringify(before) === JSON.stringify(after)\n}\n\n/**\n * 지금 편성이 **언제부터**인가.\n *\n * 저장이 전량 삭제 후 재삽입이라, 지금 행들 중 가장 이른 `createdAt` 이 곧 설치 시각이다. 행이 없으면\n * 편성이 없는 것이므로 없다고 답한다 — 지어내면 그 시각 이전의 사실이 지금 편성으로 읽힌다.\n */\nexport function inForceSince(shifts: WorkShift[]): Date | undefined {\n const times = shifts.map(shift => shift.createdAt?.getTime()).filter((time): time is number => Boolean(time))\n\n return times.length ? new Date(Math.min(...times)) : undefined\n}\n\n/**\n * 바꾸기 **전에** 지금 쓰던 편성을 남긴다.\n *\n * ── 순서가 이 함수의 전부다 ────────────────────────────────────────────────\n * 저장은 그 도메인의 교대를 전부 지우고 다시 넣는다. 지운 뒤에 남기려 하면 남길 것이 없다.\n *\n * ── 지금 쓰던 것이 편집기의 내용이 아닐 수 있다 ────────────────────────────\n * 예고한 시각이 지났으면 **예고분이 적용 중**이고, 편집기(`WorkShift`)의 내용은 그때 이미 답이 아니다.\n * 그 상태에서 편집기 내용만 이력에 남기면 실제로 쓰이던 편성이 기록에서 빠진다.\n *\n * 그리고 그 열린 벌을 닫지 않으면 **저장한 것이 적용되지 않는다** — 시각으로 고를 때 열린 벌이 계속\n * 이기기 때문이다. 사람은 저장했는데 아무것도 안 바뀌는 것을 보게 된다.\n *\n * 적용 중이던 예고분은 닫는 것만으로 이력이 된다. 따로 한 줄 더 남기면 같은 편성이 두 번 적힌다.\n */\nexport async function recordRevision(\n manager: EntityManager,\n domain: Domain,\n next: Record<string, unknown>[],\n user?: User,\n now = new Date()\n): Promise<WorkShiftRevision | undefined> {\n /* 지금 실제로 적용 중인 벌 — 편집기의 것일 수도, 시작된 예고분일 수도 있다. */\n const started = await manager.findOne(WorkShiftRevision, {\n where: { domain: { id: domain.id }, effectiveTo: IsNull() },\n order: { effectiveFrom: 'DESC' }\n })\n\n if (started && started.effectiveFrom <= now) {\n if (sameShiftSet(started.shifts, next)) {\n /* 적용 중인 예고분과 같은 내용이다. 닫으면 뒤가 빈 구간이 되므로 그대로 둔다. */\n return undefined\n }\n\n /* 닫는 것만으로 이력이 된다. 그리고 닫아야 이번 저장이 적용된다. */\n await manager.update(WorkShiftRevision, { id: started.id }, { effectiveTo: now })\n\n return { ...started, effectiveTo: now } as WorkShiftRevision\n }\n\n const current = await manager.find(WorkShift, { where: { domain: { id: domain.id } } })\n\n if (!current.length) {\n /* 첫 설치다. 지나간 편성이 없다. */\n return undefined\n }\n\n const before = shiftSetOf(current)\n\n if (sameShiftSet(before, next)) {\n /* 내용이 그대로다. 남기면 이력이 「바뀌지 않음」으로 채워져 읽을 수 없게 된다. */\n return undefined\n }\n\n return await manager.save(WorkShiftRevision, {\n domain,\n /* 언제부터 쓰던 것인가 — 모르면 그만둔 시각으로 둔다(길이 0인 구간). 지어내지 않는다. */\n effectiveFrom: inForceSince(current) ?? now,\n effectiveTo: now,\n shifts: before,\n creator: user\n } as WorkShiftRevision)\n}\n\n/** 이 도메인의 지나간 벌과 예고된 벌 전부. 고르는 일은 순수 함수가 한다. */\nasync function revisionsOf(manager: EntityManager, domain: Domain): Promise<WorkShiftRevision[]> {\n return await manager.find(WorkShiftRevision, {\n where: { domain: { id: domain.id } },\n order: { effectiveFrom: 'ASC' }\n })\n}\n\n/**\n * 그 시각에 쓰던 편성 — **지금 편성이 아닐 수 있다.**\n *\n * 지나간 시각이면 이력에서, 예고한 시각이 지났으면 예고분에서 고른다. 고르는 규칙은\n * `work-shift-selection.ts` 에 순수하게 있다.\n *\n * **이력보다 앞선 시각은 없다고 답한다.** 그때 무엇을 쓰고 있었는지 이 시스템은 모른다.\n */\nexport async function shiftsInForceAt(\n manager: EntityManager,\n domain: Domain,\n at: Date\n): Promise<{ shifts: Record<string, unknown>[]; origin: SetOrigin; from?: Date } | undefined> {\n const current = await manager.find(WorkShift, {\n where: { domain: { id: domain.id } },\n order: { fromDate: 'ASC', fromTime: 'ASC' }\n })\n\n const revisions = await revisionsOf(manager, domain)\n\n const selected = selectSetAt<Record<string, unknown>[]>(\n at,\n current.length ? shiftSetOf(current) : undefined,\n inForceSince(current),\n revisions.map(revision => ({\n effectiveFrom: revision.effectiveFrom,\n effectiveTo: revision.effectiveTo,\n shifts: revision.shifts\n }))\n )\n\n return selected.shifts ? { shifts: selected.shifts, origin: selected.origin, from: selected.from } : undefined\n}\n\n/**\n * 앞으로 쓸 편성을 미리 적어 둔다.\n *\n * ── 지난 시각으로는 예고하지 않는다 ────────────────────────────────────────\n * 지난 시각으로 넣으면 이미 적힌 사실들의 교대 이름이 통째로 바뀐다. 그것은 예고가 아니라 **기록을\n * 고치는 것**이고, 이 문으로 할 일이 아니다.\n *\n * ── 앞의 열린 벌을 닫는다 ──────────────────────────────────────────────────\n * 끝이 없는 벌이 둘이면 어느 것이 답인지 갈린다. 새 예고의 시작이 앞엣것의 끝이 된다.\n */\nexport async function announceShiftSet(\n manager: EntityManager,\n domain: Domain,\n effectiveFrom: Date,\n shifts: Record<string, unknown>[],\n user?: User,\n now = new Date()\n): Promise<WorkShiftRevision> {\n if (effectiveFrom <= now) {\n throw new Error('announceShiftSet: 예고는 앞으로의 시각으로만 한다 — 지난 시각으로 넣으면 이미 적힌 사실의 교대가 바뀐다')\n }\n\n if (!shifts.length) {\n throw new Error('announceShiftSet: 빈 편성은 예고할 수 없다 — 그 시각부터 교대가 없다는 뜻이 되어 버린다')\n }\n\n const open = await manager.findOne(WorkShiftRevision, {\n where: { domain: { id: domain.id }, effectiveTo: IsNull() },\n order: { effectiveFrom: 'DESC' }\n })\n\n if (open) {\n if (open.effectiveFrom >= effectiveFrom) {\n throw new Error(\n 'announceShiftSet: 이미 더 늦은 예고가 있다 — 그것을 먼저 물리고 다시 예고한다'\n )\n }\n\n /* 앞의 열린 벌은 새 예고가 시작하는 시각에 끝난다. */\n await manager.update(WorkShiftRevision, { id: open.id }, { effectiveTo: effectiveFrom })\n }\n\n return await manager.save(WorkShiftRevision, {\n domain,\n effectiveFrom,\n effectiveTo: null,\n shifts,\n creator: user\n } as unknown as WorkShiftRevision)\n}\n\n/**\n * 예고를 물린다.\n *\n * **아직 시작하지 않은 것만** 물릴 수 있다. 이미 적용 중인 벌을 지우면 그 사이에 적힌 사실들이 가리키던\n * 편성이 사라진다 — 그때는 지우는 것이 아니라 새로 예고하거나 지금 편성을 저장한다.\n */\nexport async function cancelAnnouncement(\n manager: EntityManager,\n domain: Domain,\n id: string,\n now = new Date()\n): Promise<boolean> {\n const found = await manager.findOne(WorkShiftRevision, { where: { id, domain: { id: domain.id } } })\n\n if (!found) {\n return false\n }\n\n if (found.effectiveFrom <= now) {\n throw new Error('cancelAnnouncement: 이미 적용된 편성은 물릴 수 없다 — 그 사이에 적힌 사실이 이것을 가리킨다')\n }\n\n await manager.delete(WorkShiftRevision, { id: found.id })\n\n /* 앞의 벌이 이 예고 때문에 닫혀 있었다면 다시 열어 준다 — 아니면 그 뒤가 빈 구간이 된다. */\n const previous = await manager.findOne(WorkShiftRevision, {\n where: { domain: { id: domain.id }, effectiveTo: found.effectiveFrom },\n order: { effectiveFrom: 'DESC' }\n })\n\n if (previous) {\n await manager.update(WorkShiftRevision, { id: previous.id }, { effectiveTo: null })\n }\n\n return true\n}\n\n/** 아직 시작하지 않은 벌들 — 화면이 「예고된 편성」으로 보여 줄 것. */\nexport async function announcementsOf(\n manager: EntityManager,\n domain: Domain,\n now = new Date()\n): Promise<WorkShiftRevision[]> {\n return announcedSets(now, await revisionsOf(manager, domain)) as WorkShiftRevision[]\n}\n"]}
1
+ {"version":3,"file":"work-shift-revision-service.js","sourceRoot":"","sources":["../../../server/service/work-shift/work-shift-revision-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager } from 'typeorm'\nimport { Domain } from '@things-factory/shell'\nimport { WorkShift } from './work-shift'\nimport { WorkShiftArrangement } from './work-shift-arrangement'\nimport { WorkShiftPlan, WorkShiftSegment } from './work-shift-revision'\nimport { WorkShiftRefusal, resolveWorkShift, workShiftSubmissionHash } from './work-shift-lifecycle'\nimport { shiftOccurrence } from './shift-occurrence'\nimport moment from 'moment-timezone'\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}\nexport function sameShiftSet(a: Record<string, unknown>[], b: Record<string, unknown>[]) { return JSON.stringify(a) === JSON.stringify(b) }\nexport async function shiftsInForceAt(manager: EntityManager, domain: Domain, at: Date) {\n const root = await manager.findOneBy(WorkShiftArrangement, { domain: { id: domain.id } })\n if (!root || !root.planGeneration) return undefined\n try {\n const selected = await resolveWorkShift(manager, domain.id, root.id, at)\n return { shifts: selected.revision.shifts, timezone: selected.revision.timezone,\n origin: 'revision' as const, from: selected.segment.validFrom, to: selected.segment.validTo,\n revisionId: selected.revision.id, revisionNumber: selected.revision.revisionNumber,\n creatorId: selected.revision.creatorId, createdAt: selected.revision.createdAt }\n } catch (error) {\n if (error instanceof WorkShiftRefusal && error.code === 'NO_EFFECTIVE_REVISION') return undefined\n throw error\n }\n}\n\nexport async function effectiveWorkShifts(manager: EntityManager, domain: Domain, at = new Date()): Promise<WorkShift[]> {\n const selected = await shiftsInForceAt(manager, domain, at)\n return (selected?.shifts ?? []).map(shift => Object.assign(new WorkShift(), shift, {\n id: selected.revisionId + '/' + shift.name, domain, domainId: domain.id,\n creatorId: selected.creatorId, updaterId: selected.creatorId,\n createdAt: selected.createdAt, updatedAt: selected.createdAt\n }))\n}\n\n/** Bounded expansion for OEE/planning windows; absolute intervals preserve zone/DST and revision boundaries. */\nexport async function shiftArrangementsDuring(manager: EntityManager, domain: Domain, from: Date, to: Date) {\n if (!(to > from) || to.getTime() - from.getTime() > 366 * 86400000) throw new WorkShiftRefusal('INVALID_INSTANT', 'Choose a window of at most 366 days.')\n const root = await manager.findOneBy(WorkShiftArrangement, { domain: { id: domain.id } })\n if (!root?.planGeneration) return []\n const plan = await manager.findOneByOrFail(WorkShiftPlan, { domain: { id: domain.id }, arrangement: { id: root.id }, generation: root.planGeneration })\n const segments = await manager.createQueryBuilder(WorkShiftSegment, 's').innerJoinAndSelect('s.revision', 'r')\n .where('s.plan_id = :id AND s.domain_id = :domainId', { id: plan.id, domainId: domain.id })\n .andWhere('s.validFrom < :to AND (s.validTo IS NULL OR s.validTo > :from)', { from, to }).getMany()\n return segments.map(segment => {\n const revision = segment.revision\n if (!revision.frozenAt || revision.contentHash !== workShiftSubmissionHash(revision)) throw new WorkShiftRefusal('REVISION_INTEGRITY_FAILURE')\n const begin = new Date(Math.max(from.getTime(), segment.validFrom.getTime()))\n const end = new Date(Math.min(to.getTime(), segment.validTo?.getTime() ?? Infinity))\n const cursor = moment(begin).tz(revision.timezone).startOf('day').subtract(1, 'day')\n const last = moment(end).tz(revision.timezone).startOf('day').add(1, 'day')\n const occurrences: { name: string; from: Date; to: Date }[] = []\n for (; cursor <= last; cursor.add(1, 'day')) for (const shift of revision.shifts) {\n const w = shiftOccurrence(shift, cursor.format('YYYY-MM-DD'), revision.timezone)\n if (!w) continue\n const left = new Date(Math.max(begin.getTime(), w.from.getTime())), right = new Date(Math.min(end.getTime(), w.to.getTime()))\n if (right > left) occurrences.push({ name: w.name, from: left, to: right })\n }\n return { revision, segment, occurrences }\n })\n}\n/** Old mutation/service entry points must never rewrite a signed schedule. */\nexport async function recordRevision(..._args: any[]): Promise<never> { throw new WorkShiftRefusal('REVISION_REQUIRED') }\nexport async function announceShiftSet(..._args: any[]): Promise<never> { throw new WorkShiftRefusal('REVISION_REQUIRED') }\nexport async function cancelAnnouncement(..._args: any[]): Promise<never> { throw new WorkShiftRefusal('REVISION_REQUIRED') }\n"]}
@@ -1,67 +1,83 @@
1
1
  import { Domain } from '@things-factory/shell';
2
2
  import { User } from '@things-factory/auth-base';
3
- /**
4
- * 교대 편성 벌 — **지나간 것과 예고된 것.**
5
- *
6
- * ── 무엇이 사라지고 있었나 ─────────────────────────────────────────────────
7
- * `updateMultipleWorkShift` 는 그 도메인의 교대를 **전부 지우고 다시 넣는다.** 오탈자 하나를 고쳐도
8
- * 이전 편성이 데이터베이스에서 없어진다. 그래서 이런 물음에 답할 수 없었다.
9
- *
10
- * 6월 실적의 「주간」은 몇 시부터 몇 시였나
11
- * 3교대로 바꾼 것이 언제부터인가
12
- * 누가 언제 편성을 바꿨나
13
- *
14
- * ── 왜 유효기간 칸이 아니라 별도 표인가 ────────────────────────────────────
15
- * `WorkShift` 에 `effectiveStart`/`effectiveEnd` 를 다는 길도 있었다. 그러려면 유니크 인덱스 둘
16
- * (`[domain, name]` · `[domain, fromDate, fromTime]`)을 풀어야 한다 — 같은 이름이 기간별로 여러 행이어야
17
- * 하기 때문이다. **그 인덱스는 지금 잘못된 편성을 막고 있는 가드**이고, 다섯 드라이버에서 그것을
18
- * 풀면서 코드로 대신 지키는 것은 얻는 것보다 잃는 것이 크다.
19
- *
20
- * 별도 표는 `WorkShift` 를 **한 글자도 건드리지 않는다.** 지금 쓰는 편성은 그대로 그 표에 있고, 이
21
- * 표에는 **지나간 것만** 쌓인다. 그래서 두 곳이 어긋날 수가 없다.
22
- *
23
- * ── 행이 아니라 벌이 단위다 ────────────────────────────────────────────────
24
- * 교대는 한 줄씩 바뀌지 않는다. 「2교대에서 3교대로」처럼 **편성 전체가** 바뀐다. 그래서 이 표의 한 행이
25
- * 그때 쓰던 편성 한 벌이다.
26
- *
27
- * ── 지금 쓰는 편성은 여기 없다 ─────────────────────────────────────────────
28
- * 넣으면 같은 사실이 두 곳에 살고, 둘이 어긋나는 날이 온다. 지금 편성이 **언제부터**인지는 `WorkShift`
29
- * 행들의 `createdAt` 중 가장 이른 것이 말해 준다 — 전량 삭제 후 재삽입이라 그 값이 곧 설치 시각이다.
30
- *
31
- * ── 앞으로 쓸 편성도 여기 든다 ─────────────────────────────────────────────
32
- * 「다음 달 1일부터 3교대」를 미리 적어 둘 수 있어야 한다. 그러지 못하면 바뀌는 날 자정에 사람이 손으로
33
- * 고쳐야 하고, 그 시각에 도는 창이 어긋난다.
34
- *
35
- * 예고된 벌은 `effectiveFrom` 이 미래이고 `effectiveTo` 가 비어 있다. **바뀌는 날 무엇을 옮기는 일이
36
- * 없다** — 시각으로 고르기 때문에 그 시각이 지나면 저절로 그 벌이 답이 된다. 자정에 도는 일감을 두면
37
- * 그날 서버가 내려가 있을 때 편성이 안 바뀌고, 아무도 그것을 모른다.
38
- *
39
- * ```
40
- * 지나간 것 effectiveFrom ≤ effectiveTo ≤ 지금
41
- * 예고된 것 effectiveFrom > 지금 · effectiveTo 없음
42
- * ```
43
- */
3
+ import { WorkShiftArrangement } from './work-shift-arrangement';
4
+ import { MasterChangePolicy } from '@things-factory/ops-master';
5
+ /** Content and the proposed effective date freeze together. Worklist owns the decision. */
44
6
  export declare class WorkShiftRevision {
45
- readonly id: string;
46
- domain?: Domain;
47
- domainId?: string;
48
- /** 이 편성을 쓰기 시작한 시각. */
7
+ /** Human revision number within one identity; assigned once under the subject write lock. */
8
+ revisionNumber: number;
9
+ policy: MasterChangePolicy;
10
+ policyId: string;
11
+ id: string;
12
+ domain: Domain;
13
+ domainId: string;
14
+ arrangement: WorkShiftArrangement;
15
+ arrangementId: string;
16
+ baseRevision: WorkShiftRevision | null;
17
+ baseRevisionId: string | null;
18
+ baseGeneration: number;
19
+ editGeneration: number;
20
+ description: string | null;
21
+ timezone: string;
22
+ shifts: import('./work-shift-content').ShiftDefinition[];
49
23
  effectiveFrom: Date;
50
- /**
51
- * 이 편성을 그만 쓴 시각. **예고된 벌은 비어 있다** — 아직 끝나지 않았다.
52
- *
53
- * 비어 있는 벌이 둘이면 어느 것이 답인지 갈리므로, 새 예고를 넣을 때 앞의 열린 벌을 닫는다.
54
- */
55
- effectiveTo?: Date;
56
- /**
57
- * 그때 쓰던 교대 한 벌 — `[{ name, fromDate, fromTime, toDate, toTime }]`.
58
- *
59
- * `WorkShift` 를 가리키는 참조로 두지 않는다. 그 행들은 이미 지워졌고, 지워진 것을 가리키는 참조는
60
- * 아무것도 답하지 못한다.
61
- */
62
- shifts: Record<string, unknown>[];
63
- createdAt?: Date;
64
- /** 누가 바꿨나. 앞서는 전량 삭제 때문에 이것도 매번 사라졌다. */
65
- creator?: User;
66
- creatorId?: string;
24
+ reason: string;
25
+ creator: User;
26
+ creatorId: string;
27
+ createdAt: Date;
28
+ frozenAt: Date | null;
29
+ contentHash: string | null;
30
+ /** Opaque product decision ID: the common master module does not depend on worklist. */
31
+ activityInstanceId: string | null;
67
32
  }
33
+ /** An append-only generation of the complete schedule for one arrangement. */
34
+ export declare class WorkShiftPlan {
35
+ policy: MasterChangePolicy;
36
+ policyId: string;
37
+ publishedRevision: WorkShiftRevision;
38
+ publishedRevisionId: string;
39
+ releaseKind: 'approved' | 'policy';
40
+ publisher: User;
41
+ publisherId: string;
42
+ id: string;
43
+ domain: Domain;
44
+ domainId: string;
45
+ arrangement: WorkShiftArrangement;
46
+ arrangementId: string;
47
+ generation: number;
48
+ recordedAt: Date;
49
+ activityInstanceId: string | null;
50
+ approver: User;
51
+ approverId: string;
52
+ submissionHash: string;
53
+ }
54
+ export declare class WorkShiftSegment {
55
+ id: string;
56
+ domain: Domain;
57
+ domainId: string;
58
+ arrangement: WorkShiftArrangement;
59
+ arrangementId: string;
60
+ plan: WorkShiftPlan;
61
+ planId: string;
62
+ revision: WorkShiftRevision;
63
+ revisionId: string;
64
+ validFrom: Date;
65
+ validTo: Date | null;
66
+ }
67
+ /** Permanent evidence of the selected revision, also the retroactivity interlock. */
68
+ export declare class WorkShiftBasis {
69
+ id: string;
70
+ domain: Domain;
71
+ domainId: string;
72
+ arrangement: WorkShiftArrangement;
73
+ arrangementId: string;
74
+ recordKey: string;
75
+ revision: WorkShiftRevision;
76
+ revisionId: string;
77
+ plan: WorkShiftPlan;
78
+ planId: string;
79
+ contentHash: string;
80
+ businessTime: Date;
81
+ resolvedAt: Date;
82
+ }
83
+ export declare const WORK_SHIFT_REVISION_ENTITIES: (typeof WorkShiftRevision | typeof WorkShiftPlan | typeof WorkShiftSegment | typeof WorkShiftBasis)[];
@@ -1,116 +1,337 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WorkShiftRevision = void 0;
3
+ exports.WORK_SHIFT_REVISION_ENTITIES = exports.WorkShiftBasis = exports.WorkShiftSegment = exports.WorkShiftPlan = exports.WorkShiftRevision = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const typeorm_1 = require("typeorm");
6
- const type_graphql_1 = require("type-graphql");
7
6
  const shell_1 = require("@things-factory/shell");
8
7
  const auth_base_1 = require("@things-factory/auth-base");
9
- /**
10
- * 교대 편성 한 벌 — **지나간 것과 예고된 것.**
11
- *
12
- * ── 무엇이 사라지고 있었나 ─────────────────────────────────────────────────
13
- * `updateMultipleWorkShift` 도메인의 교대를 **전부 지우고 다시 넣는다.** 오탈자 하나를 고쳐도
14
- * 이전 편성이 데이터베이스에서 없어진다. 그래서 이런 물음에 답할 없었다.
15
- *
16
- * 6월 실적의 「주간」은 몇 시부터 몇 시였나
17
- * 3교대로 바꾼 것이 언제부터인가
18
- * 누가 언제 편성을 바꿨나
19
- *
20
- * ── 왜 유효기간 칸이 아니라 별도 표인가 ────────────────────────────────────
21
- * `WorkShift` 에 `effectiveStart`/`effectiveEnd` 를 다는 길도 있었다. 그러려면 유니크 인덱스 둘
22
- * (`[domain, name]` · `[domain, fromDate, fromTime]`)을 풀어야 한다 — 같은 이름이 기간별로 여러 행이어야
23
- * 하기 때문이다. **그 인덱스는 지금 잘못된 편성을 막고 있는 가드**이고, 다섯 드라이버에서 그것을
24
- * 풀면서 코드로 대신 지키는 것은 얻는 것보다 잃는 것이 크다.
25
- *
26
- * 별도 표는 `WorkShift` 를 **한 글자도 건드리지 않는다.** 지금 쓰는 편성은 그대로 그 표에 있고, 이
27
- * 표에는 **지나간 것만** 쌓인다. 그래서 두 곳이 어긋날 수가 없다.
28
- *
29
- * ── 행이 아니라 벌이 단위다 ────────────────────────────────────────────────
30
- * 교대는 한 줄씩 바뀌지 않는다. 「2교대에서 3교대로」처럼 **편성 전체가** 바뀐다. 그래서 이 표의 한 행이
31
- * 그때 쓰던 편성 한 벌이다.
32
- *
33
- * ── 지금 쓰는 편성은 여기 없다 ─────────────────────────────────────────────
34
- * 넣으면 같은 사실이 두 곳에 살고, 둘이 어긋나는 날이 온다. 지금 편성이 **언제부터**인지는 `WorkShift`
35
- * 행들의 `createdAt` 중 가장 이른 것이 말해 준다 — 전량 삭제 후 재삽입이라 그 값이 곧 설치 시각이다.
36
- *
37
- * ── 앞으로 쓸 편성도 여기 든다 ─────────────────────────────────────────────
38
- * 「다음 달 1일부터 3교대」를 미리 적어 둘 수 있어야 한다. 그러지 못하면 바뀌는 날 자정에 사람이 손으로
39
- * 고쳐야 하고, 그 시각에 도는 창이 어긋난다.
40
- *
41
- * 예고된 벌은 `effectiveFrom` 이 미래이고 `effectiveTo` 가 비어 있다. **바뀌는 날 무엇을 옮기는 일이
42
- * 없다** — 시각으로 고르기 때문에 그 시각이 지나면 저절로 그 벌이 답이 된다. 자정에 도는 일감을 두면
43
- * 그날 서버가 내려가 있을 때 편성이 안 바뀌고, 아무도 그것을 모른다.
44
- *
45
- * ```
46
- * 지나간 것 effectiveFrom ≤ effectiveTo ≤ 지금
47
- * 예고된 것 effectiveFrom > 지금 · effectiveTo 없음
48
- * ```
49
- */
8
+ const work_shift_arrangement_1 = require("./work-shift-arrangement");
9
+ const ops_master_1 = require("@things-factory/ops-master");
10
+ // Relations own the columns and RelationId exposes read-only identifiers.
11
+ // Where a composite FK is declared, disable only the redundant single-column FK;
12
+ // the database still enforces existence, domain and arrangement together.
13
+ /** Content and the proposed effective date freeze together. Worklist owns the decision. */
50
14
  let WorkShiftRevision = class WorkShiftRevision {
51
15
  };
52
16
  exports.WorkShiftRevision = WorkShiftRevision;
17
+ tslib_1.__decorate([
18
+ (0, typeorm_1.Column)('int'),
19
+ tslib_1.__metadata("design:type", Number)
20
+ ], WorkShiftRevision.prototype, "revisionNumber", void 0);
21
+ tslib_1.__decorate([
22
+ (0, typeorm_1.ManyToOne)(() => ops_master_1.MasterChangePolicy, { nullable: false, createForeignKeyConstraints: false }),
23
+ tslib_1.__metadata("design:type", ops_master_1.MasterChangePolicy)
24
+ ], WorkShiftRevision.prototype, "policy", void 0);
25
+ tslib_1.__decorate([
26
+ (0, typeorm_1.RelationId)((row) => row.policy),
27
+ tslib_1.__metadata("design:type", String)
28
+ ], WorkShiftRevision.prototype, "policyId", void 0);
53
29
  tslib_1.__decorate([
54
30
  (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
55
- (0, type_graphql_1.Field)(type => type_graphql_1.ID),
56
31
  tslib_1.__metadata("design:type", String)
57
32
  ], WorkShiftRevision.prototype, "id", void 0);
58
33
  tslib_1.__decorate([
59
- (0, typeorm_1.ManyToOne)(type => shell_1.Domain),
60
- (0, type_graphql_1.Field)(type => shell_1.Domain),
34
+ (0, typeorm_1.ManyToOne)(() => shell_1.Domain, { nullable: false }),
61
35
  tslib_1.__metadata("design:type", shell_1.Domain)
62
36
  ], WorkShiftRevision.prototype, "domain", void 0);
63
37
  tslib_1.__decorate([
64
- (0, typeorm_1.RelationId)((revision) => revision.domain),
38
+ (0, typeorm_1.RelationId)((row) => row.domain),
65
39
  tslib_1.__metadata("design:type", String)
66
40
  ], WorkShiftRevision.prototype, "domainId", void 0);
41
+ tslib_1.__decorate([
42
+ (0, typeorm_1.ManyToOne)('WorkShiftArrangement', { nullable: false, createForeignKeyConstraints: false }),
43
+ tslib_1.__metadata("design:type", work_shift_arrangement_1.WorkShiftArrangement)
44
+ ], WorkShiftRevision.prototype, "arrangement", void 0);
45
+ tslib_1.__decorate([
46
+ (0, typeorm_1.RelationId)((row) => row.arrangement),
47
+ tslib_1.__metadata("design:type", String)
48
+ ], WorkShiftRevision.prototype, "arrangementId", void 0);
49
+ tslib_1.__decorate([
50
+ (0, typeorm_1.ManyToOne)(() => WorkShiftRevision, { nullable: true, createForeignKeyConstraints: false }),
51
+ tslib_1.__metadata("design:type", WorkShiftRevision)
52
+ ], WorkShiftRevision.prototype, "baseRevision", void 0);
53
+ tslib_1.__decorate([
54
+ (0, typeorm_1.RelationId)((row) => row.baseRevision),
55
+ tslib_1.__metadata("design:type", String)
56
+ ], WorkShiftRevision.prototype, "baseRevisionId", void 0);
57
+ tslib_1.__decorate([
58
+ (0, typeorm_1.Column)('int'),
59
+ tslib_1.__metadata("design:type", Number)
60
+ ], WorkShiftRevision.prototype, "baseGeneration", void 0);
61
+ tslib_1.__decorate([
62
+ (0, typeorm_1.Column)('int', { default: 0 }),
63
+ tslib_1.__metadata("design:type", Number)
64
+ ], WorkShiftRevision.prototype, "editGeneration", void 0);
65
+ tslib_1.__decorate([
66
+ (0, typeorm_1.Column)('text', { nullable: true }),
67
+ tslib_1.__metadata("design:type", String)
68
+ ], WorkShiftRevision.prototype, "description", void 0);
67
69
  tslib_1.__decorate([
68
70
  (0, typeorm_1.Column)(),
69
- (0, type_graphql_1.Field)(),
70
- tslib_1.__metadata("design:type", Date
71
- /**
72
- * 이 편성을 그만 쓴 시각. **예고된 벌은 비어 있다** — 아직 끝나지 않았다.
73
- *
74
- * 비어 있는 벌이 둘이면 어느 것이 답인지 갈리므로, 새 예고를 넣을 때 앞의 열린 벌을 닫는다.
75
- */
76
- )
77
- ], WorkShiftRevision.prototype, "effectiveFrom", void 0);
71
+ tslib_1.__metadata("design:type", String)
72
+ ], WorkShiftRevision.prototype, "timezone", void 0);
78
73
  tslib_1.__decorate([
79
- (0, typeorm_1.Column)({ nullable: true }),
80
- (0, type_graphql_1.Field)({ nullable: true }),
81
- tslib_1.__metadata("design:type", Date
82
- /**
83
- * 그때 쓰던 교대 한 벌 — `[{ name, fromDate, fromTime, toDate, toTime }]`.
84
- *
85
- * `WorkShift` 를 가리키는 참조로 두지 않는다. 그 행들은 이미 지워졌고, 지워진 것을 가리키는 참조는
86
- * 아무것도 답하지 못한다.
87
- */
88
- )
89
- ], WorkShiftRevision.prototype, "effectiveTo", void 0);
90
- tslib_1.__decorate([
91
- (0, typeorm_1.Column)({ type: 'simple-json' }),
92
- (0, type_graphql_1.Field)(type => String, { description: 'the shift set that was in force, as JSON text' }),
74
+ (0, typeorm_1.Column)('simple-json'),
93
75
  tslib_1.__metadata("design:type", Array)
94
76
  ], WorkShiftRevision.prototype, "shifts", void 0);
95
77
  tslib_1.__decorate([
96
- (0, typeorm_1.CreateDateColumn)(),
97
- (0, type_graphql_1.Field)({ nullable: true }),
98
- tslib_1.__metadata("design:type", Date
99
- /** 누가 바꿨나. 앞서는 전량 삭제 때문에 이것도 매번 사라졌다. */
100
- )
101
- ], WorkShiftRevision.prototype, "createdAt", void 0);
78
+ (0, typeorm_1.Column)({ type: Date }),
79
+ tslib_1.__metadata("design:type", Date)
80
+ ], WorkShiftRevision.prototype, "effectiveFrom", void 0);
81
+ tslib_1.__decorate([
82
+ (0, typeorm_1.Column)('text'),
83
+ tslib_1.__metadata("design:type", String)
84
+ ], WorkShiftRevision.prototype, "reason", void 0);
102
85
  tslib_1.__decorate([
103
- (0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
104
- (0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true }),
86
+ (0, typeorm_1.ManyToOne)(() => auth_base_1.User, { nullable: false }),
105
87
  tslib_1.__metadata("design:type", auth_base_1.User)
106
88
  ], WorkShiftRevision.prototype, "creator", void 0);
107
89
  tslib_1.__decorate([
108
- (0, typeorm_1.RelationId)((revision) => revision.creator),
90
+ (0, typeorm_1.RelationId)((row) => row.creator),
109
91
  tslib_1.__metadata("design:type", String)
110
92
  ], WorkShiftRevision.prototype, "creatorId", void 0);
93
+ tslib_1.__decorate([
94
+ (0, typeorm_1.Column)({ type: Date }),
95
+ tslib_1.__metadata("design:type", Date)
96
+ ], WorkShiftRevision.prototype, "createdAt", void 0);
97
+ tslib_1.__decorate([
98
+ (0, typeorm_1.Column)({ type: Date, nullable: true }),
99
+ tslib_1.__metadata("design:type", Date)
100
+ ], WorkShiftRevision.prototype, "frozenAt", void 0);
101
+ tslib_1.__decorate([
102
+ (0, typeorm_1.Column)('varchar', { nullable: true }),
103
+ tslib_1.__metadata("design:type", String)
104
+ ], WorkShiftRevision.prototype, "contentHash", void 0);
105
+ tslib_1.__decorate([
106
+ (0, typeorm_1.Column)('varchar', { nullable: true }),
107
+ tslib_1.__metadata("design:type", String)
108
+ ], WorkShiftRevision.prototype, "activityInstanceId", void 0);
111
109
  exports.WorkShiftRevision = WorkShiftRevision = tslib_1.__decorate([
112
- (0, typeorm_1.Entity)(),
113
- (0, typeorm_1.Index)('ix_work_shift_revision_0', (revision) => [revision.domain, revision.effectiveFrom]),
114
- (0, type_graphql_1.ObjectType)({ description: 'A work shift arrangement that used to be in force' })
110
+ (0, typeorm_1.Entity)('work_shift_revisions'),
111
+ (0, typeorm_1.Index)('ix_arrangement_revision_subject', ['domain', 'arrangement', 'id'], { unique: true }),
112
+ (0, typeorm_1.Index)('ix_arrangement_revision_list', ['domain', 'arrangement', 'createdAt']),
113
+ (0, typeorm_1.ForeignKey)(() => ops_master_1.MasterChangePolicy, ['domain', 'policy'], ['domain', 'id'], { onDelete: 'RESTRICT' }),
114
+ (0, typeorm_1.ForeignKey)('WorkShiftArrangement', ['domain', 'arrangement'], ['domain', 'id'], { onDelete: 'RESTRICT' }),
115
+ (0, typeorm_1.ForeignKey)('WorkShiftRevision', ['domain', 'arrangement', 'baseRevision'], ['domain', 'arrangement', 'id'], {
116
+ onDelete: 'RESTRICT'
117
+ }),
118
+ (0, typeorm_1.Index)('ix_arrangement_revision_number', ['domain', 'arrangement', 'revisionNumber'], { unique: true })
115
119
  ], WorkShiftRevision);
120
+ /** An append-only generation of the complete schedule for one arrangement. */
121
+ let WorkShiftPlan = class WorkShiftPlan {
122
+ };
123
+ exports.WorkShiftPlan = WorkShiftPlan;
124
+ tslib_1.__decorate([
125
+ (0, typeorm_1.ManyToOne)(() => ops_master_1.MasterChangePolicy, { nullable: false, createForeignKeyConstraints: false }),
126
+ tslib_1.__metadata("design:type", ops_master_1.MasterChangePolicy)
127
+ ], WorkShiftPlan.prototype, "policy", void 0);
128
+ tslib_1.__decorate([
129
+ (0, typeorm_1.RelationId)((row) => row.policy),
130
+ tslib_1.__metadata("design:type", String)
131
+ ], WorkShiftPlan.prototype, "policyId", void 0);
132
+ tslib_1.__decorate([
133
+ (0, typeorm_1.ManyToOne)(() => WorkShiftRevision, { nullable: false, createForeignKeyConstraints: false }),
134
+ tslib_1.__metadata("design:type", WorkShiftRevision)
135
+ ], WorkShiftPlan.prototype, "publishedRevision", void 0);
136
+ tslib_1.__decorate([
137
+ (0, typeorm_1.RelationId)((row) => row.publishedRevision),
138
+ tslib_1.__metadata("design:type", String)
139
+ ], WorkShiftPlan.prototype, "publishedRevisionId", void 0);
140
+ tslib_1.__decorate([
141
+ (0, typeorm_1.Column)('varchar'),
142
+ tslib_1.__metadata("design:type", String)
143
+ ], WorkShiftPlan.prototype, "releaseKind", void 0);
144
+ tslib_1.__decorate([
145
+ (0, typeorm_1.ManyToOne)(() => auth_base_1.User, { nullable: false }),
146
+ tslib_1.__metadata("design:type", auth_base_1.User)
147
+ ], WorkShiftPlan.prototype, "publisher", void 0);
148
+ tslib_1.__decorate([
149
+ (0, typeorm_1.RelationId)((row) => row.publisher),
150
+ tslib_1.__metadata("design:type", String)
151
+ ], WorkShiftPlan.prototype, "publisherId", void 0);
152
+ tslib_1.__decorate([
153
+ (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
154
+ tslib_1.__metadata("design:type", String)
155
+ ], WorkShiftPlan.prototype, "id", void 0);
156
+ tslib_1.__decorate([
157
+ (0, typeorm_1.ManyToOne)(() => shell_1.Domain, { nullable: false }),
158
+ tslib_1.__metadata("design:type", shell_1.Domain)
159
+ ], WorkShiftPlan.prototype, "domain", void 0);
160
+ tslib_1.__decorate([
161
+ (0, typeorm_1.RelationId)((row) => row.domain),
162
+ tslib_1.__metadata("design:type", String)
163
+ ], WorkShiftPlan.prototype, "domainId", void 0);
164
+ tslib_1.__decorate([
165
+ (0, typeorm_1.ManyToOne)('WorkShiftArrangement', { nullable: false, createForeignKeyConstraints: false }),
166
+ tslib_1.__metadata("design:type", work_shift_arrangement_1.WorkShiftArrangement)
167
+ ], WorkShiftPlan.prototype, "arrangement", void 0);
168
+ tslib_1.__decorate([
169
+ (0, typeorm_1.RelationId)((row) => row.arrangement),
170
+ tslib_1.__metadata("design:type", String)
171
+ ], WorkShiftPlan.prototype, "arrangementId", void 0);
172
+ tslib_1.__decorate([
173
+ (0, typeorm_1.Column)('int'),
174
+ tslib_1.__metadata("design:type", Number)
175
+ ], WorkShiftPlan.prototype, "generation", void 0);
176
+ tslib_1.__decorate([
177
+ (0, typeorm_1.Column)({ type: Date }),
178
+ tslib_1.__metadata("design:type", Date)
179
+ ], WorkShiftPlan.prototype, "recordedAt", void 0);
180
+ tslib_1.__decorate([
181
+ (0, typeorm_1.Column)('varchar', { nullable: true }),
182
+ tslib_1.__metadata("design:type", String)
183
+ ], WorkShiftPlan.prototype, "activityInstanceId", void 0);
184
+ tslib_1.__decorate([
185
+ (0, typeorm_1.ManyToOne)(() => auth_base_1.User, { nullable: true }),
186
+ tslib_1.__metadata("design:type", auth_base_1.User)
187
+ ], WorkShiftPlan.prototype, "approver", void 0);
188
+ tslib_1.__decorate([
189
+ (0, typeorm_1.RelationId)((row) => row.approver),
190
+ tslib_1.__metadata("design:type", String)
191
+ ], WorkShiftPlan.prototype, "approverId", void 0);
192
+ tslib_1.__decorate([
193
+ (0, typeorm_1.Column)('varchar'),
194
+ tslib_1.__metadata("design:type", String)
195
+ ], WorkShiftPlan.prototype, "submissionHash", void 0);
196
+ exports.WorkShiftPlan = WorkShiftPlan = tslib_1.__decorate([
197
+ (0, typeorm_1.Entity)('work_shift_plan'),
198
+ (0, typeorm_1.Index)('ix_arrangement_plan_generation', ['domain', 'arrangement', 'generation'], { unique: true }),
199
+ (0, typeorm_1.Index)('ix_arrangement_plan_identity', ['domain', 'arrangement', 'id'], { unique: true }),
200
+ (0, typeorm_1.Index)('ix_arrangement_plan_decision', ['activityInstanceId'], { unique: true }),
201
+ (0, typeorm_1.Index)('ix_arrangement_plan_publication', ['publishedRevision'], { unique: true }),
202
+ (0, typeorm_1.ForeignKey)(() => ops_master_1.MasterChangePolicy, ['domain', 'policy'], ['domain', 'id'], { onDelete: 'RESTRICT' }),
203
+ (0, typeorm_1.ForeignKey)(() => WorkShiftRevision, ['domain', 'arrangement', 'publishedRevision'], ['domain', 'arrangement', 'id'], { onDelete: 'RESTRICT' }),
204
+ (0, typeorm_1.ForeignKey)('WorkShiftArrangement', ['domain', 'arrangement'], ['domain', 'id'], { onDelete: 'RESTRICT' })
205
+ ], WorkShiftPlan);
206
+ let WorkShiftSegment = class WorkShiftSegment {
207
+ };
208
+ exports.WorkShiftSegment = WorkShiftSegment;
209
+ tslib_1.__decorate([
210
+ (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
211
+ tslib_1.__metadata("design:type", String)
212
+ ], WorkShiftSegment.prototype, "id", void 0);
213
+ tslib_1.__decorate([
214
+ (0, typeorm_1.ManyToOne)(() => shell_1.Domain, { nullable: false }),
215
+ tslib_1.__metadata("design:type", shell_1.Domain)
216
+ ], WorkShiftSegment.prototype, "domain", void 0);
217
+ tslib_1.__decorate([
218
+ (0, typeorm_1.RelationId)((row) => row.domain),
219
+ tslib_1.__metadata("design:type", String)
220
+ ], WorkShiftSegment.prototype, "domainId", void 0);
221
+ tslib_1.__decorate([
222
+ (0, typeorm_1.ManyToOne)('WorkShiftArrangement', { nullable: false, createForeignKeyConstraints: false }),
223
+ tslib_1.__metadata("design:type", work_shift_arrangement_1.WorkShiftArrangement)
224
+ ], WorkShiftSegment.prototype, "arrangement", void 0);
225
+ tslib_1.__decorate([
226
+ (0, typeorm_1.RelationId)((row) => row.arrangement),
227
+ tslib_1.__metadata("design:type", String)
228
+ ], WorkShiftSegment.prototype, "arrangementId", void 0);
229
+ tslib_1.__decorate([
230
+ (0, typeorm_1.ManyToOne)(() => WorkShiftPlan, { nullable: false, createForeignKeyConstraints: false }),
231
+ tslib_1.__metadata("design:type", WorkShiftPlan)
232
+ ], WorkShiftSegment.prototype, "plan", void 0);
233
+ tslib_1.__decorate([
234
+ (0, typeorm_1.RelationId)((row) => row.plan),
235
+ tslib_1.__metadata("design:type", String)
236
+ ], WorkShiftSegment.prototype, "planId", void 0);
237
+ tslib_1.__decorate([
238
+ (0, typeorm_1.ManyToOne)(() => WorkShiftRevision, { nullable: false, createForeignKeyConstraints: false }),
239
+ tslib_1.__metadata("design:type", WorkShiftRevision)
240
+ ], WorkShiftSegment.prototype, "revision", void 0);
241
+ tslib_1.__decorate([
242
+ (0, typeorm_1.RelationId)((row) => row.revision),
243
+ tslib_1.__metadata("design:type", String)
244
+ ], WorkShiftSegment.prototype, "revisionId", void 0);
245
+ tslib_1.__decorate([
246
+ (0, typeorm_1.Column)({ type: Date }),
247
+ tslib_1.__metadata("design:type", Date)
248
+ ], WorkShiftSegment.prototype, "validFrom", void 0);
249
+ tslib_1.__decorate([
250
+ (0, typeorm_1.Column)({ type: Date, nullable: true }),
251
+ tslib_1.__metadata("design:type", Date)
252
+ ], WorkShiftSegment.prototype, "validTo", void 0);
253
+ exports.WorkShiftSegment = WorkShiftSegment = tslib_1.__decorate([
254
+ (0, typeorm_1.Entity)('work_shift_segment'),
255
+ (0, typeorm_1.Index)('ix_arrangement_segment_lookup', ['domain', 'arrangement', 'plan', 'validFrom']),
256
+ (0, typeorm_1.ForeignKey)('WorkShiftArrangement', ['domain', 'arrangement'], ['domain', 'id'], { onDelete: 'RESTRICT' }),
257
+ (0, typeorm_1.ForeignKey)(() => WorkShiftPlan, ['domain', 'arrangement', 'plan'], ['domain', 'arrangement', 'id'], { onDelete: 'RESTRICT' }),
258
+ (0, typeorm_1.ForeignKey)(() => WorkShiftRevision, ['domain', 'arrangement', 'revision'], ['domain', 'arrangement', 'id'], {
259
+ onDelete: 'RESTRICT'
260
+ })
261
+ ], WorkShiftSegment);
262
+ /** Permanent evidence of the selected revision, also the retroactivity interlock. */
263
+ let WorkShiftBasis = class WorkShiftBasis {
264
+ };
265
+ exports.WorkShiftBasis = WorkShiftBasis;
266
+ tslib_1.__decorate([
267
+ (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
268
+ tslib_1.__metadata("design:type", String)
269
+ ], WorkShiftBasis.prototype, "id", void 0);
270
+ tslib_1.__decorate([
271
+ (0, typeorm_1.ManyToOne)(() => shell_1.Domain, { nullable: false }),
272
+ tslib_1.__metadata("design:type", shell_1.Domain)
273
+ ], WorkShiftBasis.prototype, "domain", void 0);
274
+ tslib_1.__decorate([
275
+ (0, typeorm_1.RelationId)((row) => row.domain),
276
+ tslib_1.__metadata("design:type", String)
277
+ ], WorkShiftBasis.prototype, "domainId", void 0);
278
+ tslib_1.__decorate([
279
+ (0, typeorm_1.ManyToOne)('WorkShiftArrangement', { nullable: false, createForeignKeyConstraints: false }),
280
+ tslib_1.__metadata("design:type", work_shift_arrangement_1.WorkShiftArrangement)
281
+ ], WorkShiftBasis.prototype, "arrangement", void 0);
282
+ tslib_1.__decorate([
283
+ (0, typeorm_1.RelationId)((row) => row.arrangement),
284
+ tslib_1.__metadata("design:type", String)
285
+ ], WorkShiftBasis.prototype, "arrangementId", void 0);
286
+ tslib_1.__decorate([
287
+ (0, typeorm_1.Column)('varchar'),
288
+ tslib_1.__metadata("design:type", String)
289
+ ], WorkShiftBasis.prototype, "recordKey", void 0);
290
+ tslib_1.__decorate([
291
+ (0, typeorm_1.ManyToOne)(() => WorkShiftRevision, { nullable: false, createForeignKeyConstraints: false }),
292
+ tslib_1.__metadata("design:type", WorkShiftRevision)
293
+ ], WorkShiftBasis.prototype, "revision", void 0);
294
+ tslib_1.__decorate([
295
+ (0, typeorm_1.RelationId)((row) => row.revision),
296
+ tslib_1.__metadata("design:type", String)
297
+ ], WorkShiftBasis.prototype, "revisionId", void 0);
298
+ tslib_1.__decorate([
299
+ (0, typeorm_1.ManyToOne)(() => WorkShiftPlan, { nullable: false, createForeignKeyConstraints: false }),
300
+ tslib_1.__metadata("design:type", WorkShiftPlan)
301
+ ], WorkShiftBasis.prototype, "plan", void 0);
302
+ tslib_1.__decorate([
303
+ (0, typeorm_1.RelationId)((row) => row.plan),
304
+ tslib_1.__metadata("design:type", String)
305
+ ], WorkShiftBasis.prototype, "planId", void 0);
306
+ tslib_1.__decorate([
307
+ (0, typeorm_1.Column)('varchar'),
308
+ tslib_1.__metadata("design:type", String)
309
+ ], WorkShiftBasis.prototype, "contentHash", void 0);
310
+ tslib_1.__decorate([
311
+ (0, typeorm_1.Column)({ type: Date }),
312
+ tslib_1.__metadata("design:type", Date)
313
+ ], WorkShiftBasis.prototype, "businessTime", void 0);
314
+ tslib_1.__decorate([
315
+ (0, typeorm_1.Column)({ type: Date }),
316
+ tslib_1.__metadata("design:type", Date)
317
+ ], WorkShiftBasis.prototype, "resolvedAt", void 0);
318
+ exports.WorkShiftBasis = WorkShiftBasis = tslib_1.__decorate([
319
+ (0, typeorm_1.Entity)('work_shift_basis'),
320
+ (0, typeorm_1.Index)('ix_work_shift_basis_domain', ['domain', 'id'], { unique: true }),
321
+ (0, typeorm_1.Index)('ix_arrangement_basis_owner', ['domain', 'arrangement', 'id'], { unique: true }),
322
+ (0, typeorm_1.Index)('ix_arrangement_basis_identity', ['domain', 'id', 'revision'], { unique: true }),
323
+ (0, typeorm_1.Index)('ix_arrangement_basis_record', ['domain', 'recordKey'], { unique: true }),
324
+ (0, typeorm_1.Index)('ix_arrangement_basis_time', ['domain', 'arrangement', 'businessTime']),
325
+ (0, typeorm_1.ForeignKey)('WorkShiftArrangement', ['domain', 'arrangement'], ['domain', 'id'], { onDelete: 'RESTRICT' }),
326
+ (0, typeorm_1.ForeignKey)(() => WorkShiftPlan, ['domain', 'arrangement', 'plan'], ['domain', 'arrangement', 'id'], { onDelete: 'RESTRICT' }),
327
+ (0, typeorm_1.ForeignKey)(() => WorkShiftRevision, ['domain', 'arrangement', 'revision'], ['domain', 'arrangement', 'id'], {
328
+ onDelete: 'RESTRICT'
329
+ })
330
+ ], WorkShiftBasis);
331
+ exports.WORK_SHIFT_REVISION_ENTITIES = [
332
+ WorkShiftRevision,
333
+ WorkShiftPlan,
334
+ WorkShiftSegment,
335
+ WorkShiftBasis
336
+ ];
116
337
  //# sourceMappingURL=work-shift-revision.js.map