@things-factory/compliance 0.0.0-stage → 10.1.255
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/bootstrap.d.ts +2 -0
- package/dist-client/bootstrap.js +28 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/components/compliance-case-form.d.ts +42 -0
- package/dist-client/components/compliance-case-form.js +313 -0
- package/dist-client/components/compliance-case-form.js.map +1 -0
- package/dist-client/components/compliance-case-sheet.d.ts +35 -0
- package/dist-client/components/compliance-case-sheet.js +335 -0
- package/dist-client/components/compliance-case-sheet.js.map +1 -0
- package/dist-client/components/compliance-my-inventions.d.ts +17 -0
- package/dist-client/components/compliance-my-inventions.js +133 -0
- package/dist-client/components/compliance-my-inventions.js.map +1 -0
- package/dist-client/components/compliance-my-privacy-requests.d.ts +34 -0
- package/dist-client/components/compliance-my-privacy-requests.js +232 -0
- package/dist-client/components/compliance-my-privacy-requests.js.map +1 -0
- package/dist-client/components/compliance-my-reports.d.ts +19 -0
- package/dist-client/components/compliance-my-reports.js +137 -0
- package/dist-client/components/compliance-my-reports.js.map +1 -0
- package/dist-client/components/guide-link.d.ts +13 -0
- package/dist-client/components/guide-link.js +55 -0
- package/dist-client/components/guide-link.js.map +1 -0
- package/dist-client/components/invention-report-form.d.ts +30 -0
- package/dist-client/components/invention-report-form.js +188 -0
- package/dist-client/components/invention-report-form.js.map +1 -0
- package/dist-client/components/legal-todo.d.ts +10 -0
- package/dist-client/components/legal-todo.js +43 -0
- package/dist-client/components/legal-todo.js.map +1 -0
- package/dist-client/components/my-trainings.d.ts +18 -0
- package/dist-client/components/my-trainings.js +149 -0
- package/dist-client/components/my-trainings.js.map +1 -0
- package/dist-client/components/regulation-form.d.ts +26 -0
- package/dist-client/components/regulation-form.js +161 -0
- package/dist-client/components/regulation-form.js.map +1 -0
- package/dist-client/components/seal-use-form.d.ts +47 -0
- package/dist-client/components/seal-use-form.js +300 -0
- package/dist-client/components/seal-use-form.js.map +1 -0
- package/dist-client/components/training-attendance-form.d.ts +37 -0
- package/dist-client/components/training-attendance-form.js +186 -0
- package/dist-client/components/training-attendance-form.js.map +1 -0
- package/dist-client/components/training-certificate-form.d.ts +41 -0
- package/dist-client/components/training-certificate-form.js +198 -0
- package/dist-client/components/training-certificate-form.js.map +1 -0
- package/dist-client/components/training-session-form.d.ts +39 -0
- package/dist-client/components/training-session-form.js +270 -0
- package/dist-client/components/training-session-form.js.map +1 -0
- package/dist-client/components/training-setting-form.d.ts +45 -0
- package/dist-client/components/training-setting-form.js +175 -0
- package/dist-client/components/training-setting-form.js.map +1 -0
- package/dist-client/index.d.ts +4 -0
- package/dist-client/index.js +8 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/legal-record/dispute-calendar-source.d.ts +1 -0
- package/dist-client/legal-record/dispute-calendar-source.js +51 -0
- package/dist-client/legal-record/dispute-calendar-source.js.map +1 -0
- package/dist-client/legal-record/legal-child-grid.d.ts +31 -0
- package/dist-client/legal-record/legal-child-grid.js +76 -0
- package/dist-client/legal-record/legal-child-grid.js.map +1 -0
- package/dist-client/legal-record/legal-codes.d.ts +3 -0
- package/dist-client/legal-record/legal-codes.js +5 -0
- package/dist-client/legal-record/legal-codes.js.map +1 -0
- package/dist-client/legal-record/legal-grid.d.ts +59 -0
- package/dist-client/legal-record/legal-grid.js +68 -0
- package/dist-client/legal-record/legal-grid.js.map +1 -0
- package/dist-client/legal-record/legal-record-files.d.ts +26 -0
- package/dist-client/legal-record/legal-record-files.js +162 -0
- package/dist-client/legal-record/legal-record-files.js.map +1 -0
- package/dist-client/pages/compliance-case-list.d.ts +35 -0
- package/dist-client/pages/compliance-case-list.js +112 -0
- package/dist-client/pages/compliance-case-list.js.map +1 -0
- package/dist-client/pages/dispute-list.d.ts +57 -0
- package/dist-client/pages/dispute-list.js +156 -0
- package/dist-client/pages/dispute-list.js.map +1 -0
- package/dist-client/pages/invention-list.d.ts +57 -0
- package/dist-client/pages/invention-list.js +166 -0
- package/dist-client/pages/invention-list.js.map +1 -0
- package/dist-client/pages/legal-registration-list.d.ts +63 -0
- package/dist-client/pages/legal-registration-list.js +206 -0
- package/dist-client/pages/legal-registration-list.js.map +1 -0
- package/dist-client/pages/privacy-record-list.d.ts +52 -0
- package/dist-client/pages/privacy-record-list.js +225 -0
- package/dist-client/pages/privacy-record-list.js.map +1 -0
- package/dist-client/pages/regulation-detail.d.ts +43 -0
- package/dist-client/pages/regulation-detail.js +370 -0
- package/dist-client/pages/regulation-detail.js.map +1 -0
- package/dist-client/pages/regulation-list.d.ts +52 -0
- package/dist-client/pages/regulation-list.js +144 -0
- package/dist-client/pages/regulation-list.js.map +1 -0
- package/dist-client/pages/regulations.d.ts +49 -0
- package/dist-client/pages/regulations.js +412 -0
- package/dist-client/pages/regulations.js.map +1 -0
- package/dist-client/pages/seal-use-list.d.ts +57 -0
- package/dist-client/pages/seal-use-list.js +168 -0
- package/dist-client/pages/seal-use-list.js.map +1 -0
- package/dist-client/pages/training-list.d.ts +51 -0
- package/dist-client/pages/training-list.js +333 -0
- package/dist-client/pages/training-list.js.map +1 -0
- package/dist-client/regulation/regulation-fragments.d.ts +1 -0
- package/dist-client/regulation/regulation-fragments.js +37 -0
- package/dist-client/regulation/regulation-fragments.js.map +1 -0
- package/dist-client/regulation/regulation-guide.d.ts +19 -0
- package/dist-client/regulation/regulation-guide.js +48 -0
- package/dist-client/regulation/regulation-guide.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +36 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/training-words.d.ts +11 -0
- package/dist-client/training-words.js +11 -0
- package/dist-client/training-words.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-client/words.d.ts +15 -0
- package/dist-client/words.js +20 -0
- package/dist-client/words.js.map +1 -0
- package/dist-server/activities/index.d.ts +6 -0
- package/dist-server/activities/index.js +37 -0
- package/dist-server/activities/index.js.map +1 -0
- package/dist-server/activities/legal-todo-activity-names.d.ts +1 -0
- package/dist-server/activities/legal-todo-activity-names.js +5 -0
- package/dist-server/activities/legal-todo-activity-names.js.map +1 -0
- package/dist-server/activities/legal-todo-activity.d.ts +37 -0
- package/dist-server/activities/legal-todo-activity.js +41 -0
- package/dist-server/activities/legal-todo-activity.js.map +1 -0
- package/dist-server/activities/regulation-activity-names.d.ts +1 -0
- package/dist-server/activities/regulation-activity-names.js +5 -0
- package/dist-server/activities/regulation-activity-names.js.map +1 -0
- package/dist-server/activities/regulation-activity.d.ts +48 -0
- package/dist-server/activities/regulation-activity.js +47 -0
- package/dist-server/activities/regulation-activity.js.map +1 -0
- package/dist-server/activities/seal-use-activity-names.d.ts +2 -0
- package/dist-server/activities/seal-use-activity-names.js +6 -0
- package/dist-server/activities/seal-use-activity-names.js.map +1 -0
- package/dist-server/activities/seal-use-activity.d.ts +48 -0
- package/dist-server/activities/seal-use-activity.js +47 -0
- package/dist-server/activities/seal-use-activity.js.map +1 -0
- package/dist-server/index.d.ts +2 -0
- package/dist-server/index.js +21 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/role-tasks.d.ts +2 -0
- package/dist-server/role-tasks.js +28 -0
- package/dist-server/role-tasks.js.map +1 -0
- package/dist-server/service/common/correction.d.ts +32 -0
- package/dist-server/service/common/correction.js +98 -0
- package/dist-server/service/common/correction.js.map +1 -0
- package/dist-server/service/common/employee-reader.d.ts +11 -0
- package/dist-server/service/common/employee-reader.js +46 -0
- package/dist-server/service/common/employee-reader.js.map +1 -0
- package/dist-server/service/common/legal-todo.d.ts +19 -0
- package/dist-server/service/common/legal-todo.js +37 -0
- package/dist-server/service/common/legal-todo.js.map +1 -0
- package/dist-server/service/compliance-case/compliance-case-mutation.d.ts +9 -0
- package/dist-server/service/compliance-case/compliance-case-mutation.js +73 -0
- package/dist-server/service/compliance-case/compliance-case-mutation.js.map +1 -0
- package/dist-server/service/compliance-case/compliance-case-query.d.ts +28 -0
- package/dist-server/service/compliance-case/compliance-case-query.js +212 -0
- package/dist-server/service/compliance-case/compliance-case-query.js.map +1 -0
- package/dist-server/service/compliance-case/compliance-case-rules.d.ts +71 -0
- package/dist-server/service/compliance-case/compliance-case-rules.js +111 -0
- package/dist-server/service/compliance-case/compliance-case-rules.js.map +1 -0
- package/dist-server/service/compliance-case/compliance-case-service.d.ts +76 -0
- package/dist-server/service/compliance-case/compliance-case-service.js +425 -0
- package/dist-server/service/compliance-case/compliance-case-service.js.map +1 -0
- package/dist-server/service/compliance-case/compliance-case-type.d.ts +56 -0
- package/dist-server/service/compliance-case/compliance-case-type.js +200 -0
- package/dist-server/service/compliance-case/compliance-case-type.js.map +1 -0
- package/dist-server/service/compliance-case/compliance-case.d.ts +76 -0
- package/dist-server/service/compliance-case/compliance-case.js +260 -0
- package/dist-server/service/compliance-case/compliance-case.js.map +1 -0
- package/dist-server/service/compliance-case/index.d.ts +7 -0
- package/dist-server/service/compliance-case/index.js +17 -0
- package/dist-server/service/compliance-case/index.js.map +1 -0
- package/dist-server/service/dispute/dispute-mutation.d.ts +9 -0
- package/dist-server/service/dispute/dispute-mutation.js +64 -0
- package/dist-server/service/dispute/dispute-mutation.js.map +1 -0
- package/dist-server/service/dispute/dispute-query.d.ts +16 -0
- package/dist-server/service/dispute/dispute-query.js +124 -0
- package/dist-server/service/dispute/dispute-query.js.map +1 -0
- package/dist-server/service/dispute/dispute-rules.d.ts +20 -0
- package/dist-server/service/dispute/dispute-rules.js +42 -0
- package/dist-server/service/dispute/dispute-rules.js.map +1 -0
- package/dist-server/service/dispute/dispute-service.d.ts +17 -0
- package/dist-server/service/dispute/dispute-service.js +96 -0
- package/dist-server/service/dispute/dispute-service.js.map +1 -0
- package/dist-server/service/dispute/dispute-type.d.ts +39 -0
- package/dist-server/service/dispute/dispute-type.js +149 -0
- package/dist-server/service/dispute/dispute-type.js.map +1 -0
- package/dist-server/service/dispute/dispute.d.ts +48 -0
- package/dist-server/service/dispute/dispute.js +198 -0
- package/dist-server/service/dispute/dispute.js.map +1 -0
- package/dist-server/service/dispute/index.d.ts +5 -0
- package/dist-server/service/dispute/index.js +9 -0
- package/dist-server/service/dispute/index.js.map +1 -0
- package/dist-server/service/index.d.ts +46 -0
- package/dist-server/service/index.js +112 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/invention/index.d.ts +5 -0
- package/dist-server/service/invention/index.js +9 -0
- package/dist-server/service/invention/index.js.map +1 -0
- package/dist-server/service/invention/invention-mutation.d.ts +10 -0
- package/dist-server/service/invention/invention-mutation.js +79 -0
- package/dist-server/service/invention/invention-mutation.js.map +1 -0
- package/dist-server/service/invention/invention-query.d.ts +18 -0
- package/dist-server/service/invention/invention-query.js +141 -0
- package/dist-server/service/invention/invention-query.js.map +1 -0
- package/dist-server/service/invention/invention-rules.d.ts +28 -0
- package/dist-server/service/invention/invention-rules.js +54 -0
- package/dist-server/service/invention/invention-rules.js.map +1 -0
- package/dist-server/service/invention/invention-service.d.ts +25 -0
- package/dist-server/service/invention/invention-service.js +176 -0
- package/dist-server/service/invention/invention-service.js.map +1 -0
- package/dist-server/service/invention/invention-type.d.ts +34 -0
- package/dist-server/service/invention/invention-type.js +129 -0
- package/dist-server/service/invention/invention-type.js.map +1 -0
- package/dist-server/service/invention/invention.d.ts +55 -0
- package/dist-server/service/invention/invention.js +214 -0
- package/dist-server/service/invention/invention.js.map +1 -0
- package/dist-server/service/legal-record/attachment-readers.d.ts +1 -0
- package/dist-server/service/legal-record/attachment-readers.js +27 -0
- package/dist-server/service/legal-record/attachment-readers.js.map +1 -0
- package/dist-server/service/legal-record/days.d.ts +7 -0
- package/dist-server/service/legal-record/days.js +26 -0
- package/dist-server/service/legal-record/days.js.map +1 -0
- package/dist-server/service/legal-record/legal-record-support.d.ts +24 -0
- package/dist-server/service/legal-record/legal-record-support.js +51 -0
- package/dist-server/service/legal-record/legal-record-support.js.map +1 -0
- package/dist-server/service/legal-registration/centre-change-subscriber.d.ts +9 -0
- package/dist-server/service/legal-registration/centre-change-subscriber.js +50 -0
- package/dist-server/service/legal-registration/centre-change-subscriber.js.map +1 -0
- package/dist-server/service/legal-registration/index.d.ts +7 -0
- package/dist-server/service/legal-registration/index.js +11 -0
- package/dist-server/service/legal-registration/index.js.map +1 -0
- package/dist-server/service/legal-registration/legal-registration-mutation.d.ts +10 -0
- package/dist-server/service/legal-registration/legal-registration-mutation.js +77 -0
- package/dist-server/service/legal-registration/legal-registration-mutation.js.map +1 -0
- package/dist-server/service/legal-registration/legal-registration-query.d.ts +26 -0
- package/dist-server/service/legal-registration/legal-registration-query.js +199 -0
- package/dist-server/service/legal-registration/legal-registration-query.js.map +1 -0
- package/dist-server/service/legal-registration/legal-registration-rules.d.ts +80 -0
- package/dist-server/service/legal-registration/legal-registration-rules.js +106 -0
- package/dist-server/service/legal-registration/legal-registration-rules.js.map +1 -0
- package/dist-server/service/legal-registration/legal-registration-service.d.ts +37 -0
- package/dist-server/service/legal-registration/legal-registration-service.js +248 -0
- package/dist-server/service/legal-registration/legal-registration-service.js.map +1 -0
- package/dist-server/service/legal-registration/legal-registration-type.d.ts +55 -0
- package/dist-server/service/legal-registration/legal-registration-type.js +207 -0
- package/dist-server/service/legal-registration/legal-registration-type.js.map +1 -0
- package/dist-server/service/legal-registration/legal-registration.d.ts +76 -0
- package/dist-server/service/legal-registration/legal-registration.js +311 -0
- package/dist-server/service/legal-registration/legal-registration.js.map +1 -0
- package/dist-server/service/privacy-record/index.d.ts +5 -0
- package/dist-server/service/privacy-record/index.js +9 -0
- package/dist-server/service/privacy-record/index.js.map +1 -0
- package/dist-server/service/privacy-record/privacy-record-mutation.d.ts +7 -0
- package/dist-server/service/privacy-record/privacy-record-mutation.js +56 -0
- package/dist-server/service/privacy-record/privacy-record-mutation.js.map +1 -0
- package/dist-server/service/privacy-record/privacy-record-query.d.ts +18 -0
- package/dist-server/service/privacy-record/privacy-record-query.js +131 -0
- package/dist-server/service/privacy-record/privacy-record-query.js.map +1 -0
- package/dist-server/service/privacy-record/privacy-record-rules.d.ts +52 -0
- package/dist-server/service/privacy-record/privacy-record-rules.js +91 -0
- package/dist-server/service/privacy-record/privacy-record-rules.js.map +1 -0
- package/dist-server/service/privacy-record/privacy-record-service.d.ts +33 -0
- package/dist-server/service/privacy-record/privacy-record-service.js +133 -0
- package/dist-server/service/privacy-record/privacy-record-service.js.map +1 -0
- package/dist-server/service/privacy-record/privacy-record-type.d.ts +40 -0
- package/dist-server/service/privacy-record/privacy-record-type.js +153 -0
- package/dist-server/service/privacy-record/privacy-record-type.js.map +1 -0
- package/dist-server/service/privacy-record/privacy-record.d.ts +69 -0
- package/dist-server/service/privacy-record/privacy-record.js +245 -0
- package/dist-server/service/privacy-record/privacy-record.js.map +1 -0
- package/dist-server/service/regulation/index.d.ts +5 -0
- package/dist-server/service/regulation/index.js +9 -0
- package/dist-server/service/regulation/index.js.map +1 -0
- package/dist-server/service/regulation/regulation-mutation.d.ts +15 -0
- package/dist-server/service/regulation/regulation-mutation.js +152 -0
- package/dist-server/service/regulation/regulation-mutation.js.map +1 -0
- package/dist-server/service/regulation/regulation-query.d.ts +10 -0
- package/dist-server/service/regulation/regulation-query.js +109 -0
- package/dist-server/service/regulation/regulation-query.js.map +1 -0
- package/dist-server/service/regulation/regulation-read.d.ts +21 -0
- package/dist-server/service/regulation/regulation-read.js +111 -0
- package/dist-server/service/regulation/regulation-read.js.map +1 -0
- package/dist-server/service/regulation/regulation-rules.d.ts +83 -0
- package/dist-server/service/regulation/regulation-rules.js +170 -0
- package/dist-server/service/regulation/regulation-rules.js.map +1 -0
- package/dist-server/service/regulation/regulation-service.d.ts +63 -0
- package/dist-server/service/regulation/regulation-service.js +365 -0
- package/dist-server/service/regulation/regulation-service.js.map +1 -0
- package/dist-server/service/regulation/regulation-type.d.ts +61 -0
- package/dist-server/service/regulation/regulation-type.js +226 -0
- package/dist-server/service/regulation/regulation-type.js.map +1 -0
- package/dist-server/service/regulation/regulation.d.ts +113 -0
- package/dist-server/service/regulation/regulation.js +382 -0
- package/dist-server/service/regulation/regulation.js.map +1 -0
- package/dist-server/service/seal-use/index.d.ts +5 -0
- package/dist-server/service/seal-use/index.js +9 -0
- package/dist-server/service/seal-use/index.js.map +1 -0
- package/dist-server/service/seal-use/seal-use-mutation.d.ts +8 -0
- package/dist-server/service/seal-use/seal-use-mutation.js +69 -0
- package/dist-server/service/seal-use/seal-use-mutation.js.map +1 -0
- package/dist-server/service/seal-use/seal-use-query.d.ts +14 -0
- package/dist-server/service/seal-use/seal-use-query.js +100 -0
- package/dist-server/service/seal-use/seal-use-query.js.map +1 -0
- package/dist-server/service/seal-use/seal-use-rules.d.ts +35 -0
- package/dist-server/service/seal-use/seal-use-rules.js +64 -0
- package/dist-server/service/seal-use/seal-use-rules.js.map +1 -0
- package/dist-server/service/seal-use/seal-use-service.d.ts +20 -0
- package/dist-server/service/seal-use/seal-use-service.js +168 -0
- package/dist-server/service/seal-use/seal-use-service.js.map +1 -0
- package/dist-server/service/seal-use/seal-use-type.d.ts +24 -0
- package/dist-server/service/seal-use/seal-use-type.js +93 -0
- package/dist-server/service/seal-use/seal-use-type.js.map +1 -0
- package/dist-server/service/seal-use/seal-use.d.ts +57 -0
- package/dist-server/service/seal-use/seal-use.js +181 -0
- package/dist-server/service/seal-use/seal-use.js.map +1 -0
- package/dist-server/service/training/index.d.ts +5 -0
- package/dist-server/service/training/index.js +9 -0
- package/dist-server/service/training/index.js.map +1 -0
- package/dist-server/service/training/training-checks.d.ts +20 -0
- package/dist-server/service/training/training-checks.js +56 -0
- package/dist-server/service/training/training-checks.js.map +1 -0
- package/dist-server/service/training/training-kinds.d.ts +24 -0
- package/dist-server/service/training/training-kinds.js +42 -0
- package/dist-server/service/training/training-kinds.js.map +1 -0
- package/dist-server/service/training/training-mutation.d.ts +14 -0
- package/dist-server/service/training/training-mutation.js +140 -0
- package/dist-server/service/training/training-mutation.js.map +1 -0
- package/dist-server/service/training/training-query.d.ts +21 -0
- package/dist-server/service/training/training-query.js +196 -0
- package/dist-server/service/training/training-query.js.map +1 -0
- package/dist-server/service/training/training-read.d.ts +5 -0
- package/dist-server/service/training/training-read.js +35 -0
- package/dist-server/service/training/training-read.js.map +1 -0
- package/dist-server/service/training/training-register.d.ts +1 -0
- package/dist-server/service/training/training-register.js +27 -0
- package/dist-server/service/training/training-register.js.map +1 -0
- package/dist-server/service/training/training-rules.d.ts +72 -0
- package/dist-server/service/training/training-rules.js +143 -0
- package/dist-server/service/training/training-rules.js.map +1 -0
- package/dist-server/service/training/training-service.d.ts +98 -0
- package/dist-server/service/training/training-service.js +455 -0
- package/dist-server/service/training/training-service.js.map +1 -0
- package/dist-server/service/training/training-type.d.ts +94 -0
- package/dist-server/service/training/training-type.js +352 -0
- package/dist-server/service/training/training-type.js.map +1 -0
- package/dist-server/service/training/training.d.ts +127 -0
- package/dist-server/service/training/training.js +448 -0
- package/dist-server/service/training/training.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +61 -4
- package/things-factory.config.js +19 -0
- package/translations/en.json +612 -0
- package/translations/es.json +612 -0
- package/translations/ja.json +612 -0
- package/translations/ko.json +612 -0
- package/translations/ms.json +612 -0
- package/translations/zh.json +612 -0
- package/README.md +0 -3
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CASE_CATEGORY = exports.CASE_ENTRY_REF_TYPE = exports.CASE_REF_TYPE = void 0;
|
|
4
|
+
exports.caseViewerOf = caseViewerOf;
|
|
5
|
+
exports.factsOf = factsOf;
|
|
6
|
+
exports.caseInSight = caseInSight;
|
|
7
|
+
exports.recordCaseRead = recordCaseRead;
|
|
8
|
+
exports.caseHandlerUserIds = caseHandlerUserIds;
|
|
9
|
+
exports.insideHandlerLeft = insideHandlerLeft;
|
|
10
|
+
exports.investigationDays = investigationDays;
|
|
11
|
+
exports.caseNoticeWords = caseNoticeWords;
|
|
12
|
+
exports.reportComplianceCase = reportComplianceCase;
|
|
13
|
+
exports.recordComplianceCase = recordComplianceCase;
|
|
14
|
+
exports.handleComplianceCase = handleComplianceCase;
|
|
15
|
+
exports.addComplianceCaseEntry = addComplianceCaseEntry;
|
|
16
|
+
exports.complianceCasesFor = complianceCasesFor;
|
|
17
|
+
exports.myInvestigations = myInvestigations;
|
|
18
|
+
exports.complianceCaseFor = complianceCaseFor;
|
|
19
|
+
exports.myComplianceReports = myComplianceReports;
|
|
20
|
+
exports.casePeople = casePeople;
|
|
21
|
+
exports.investigatorChoices = investigatorChoices;
|
|
22
|
+
exports.mayReadCaseFile = mayReadCaseFile;
|
|
23
|
+
exports.complianceCasesNotInvestigated = complianceCasesNotInvestigated;
|
|
24
|
+
const typeorm_1 = require("typeorm");
|
|
25
|
+
const attachment_base_1 = require("@things-factory/attachment-base");
|
|
26
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
27
|
+
const translator_1 = require("@things-factory/i18n-base/translator");
|
|
28
|
+
const notification_1 = require("@things-factory/notification");
|
|
29
|
+
const organization_1 = require("@things-factory/organization");
|
|
30
|
+
const my_employee_js_1 = require("@things-factory/organization/dist-server/service/employee/my-employee.js");
|
|
31
|
+
const setting_base_1 = require("@things-factory/setting-base");
|
|
32
|
+
const shell_1 = require("@things-factory/shell");
|
|
33
|
+
const correction_1 = require("../common/correction");
|
|
34
|
+
const employee_reader_1 = require("../common/employee-reader");
|
|
35
|
+
const compliance_case_1 = require("./compliance-case");
|
|
36
|
+
const compliance_case_rules_1 = require("./compliance-case-rules");
|
|
37
|
+
/*
|
|
38
|
+
* 신고 사건 (ADR-0187 decision 21) and the database. Every door that hands out a case - a list, one case, a file - asks
|
|
39
|
+
* `caseSightOf` here on the server and writes the read to the audit record (ADR-0141 §3.3: the service records the
|
|
40
|
+
* targets it handled). Nothing of a case is registered for AI reading or search, and the notice of a new one carries
|
|
41
|
+
* no word of it.
|
|
42
|
+
*/
|
|
43
|
+
/** The files of a report hang on the case under this `refType`, those of the investigation on its entries (attachment-base). */
|
|
44
|
+
exports.CASE_REF_TYPE = 'ComplianceCase';
|
|
45
|
+
exports.CASE_ENTRY_REF_TYPE = 'ComplianceCaseEntry';
|
|
46
|
+
/** The privilege category of the case handlers (`compliance.case-handling`). */
|
|
47
|
+
exports.CASE_CATEGORY = 'compliance-case';
|
|
48
|
+
/* A read of a case is an event of its own; `sight` says how much was read - FULL or PARTY. */
|
|
49
|
+
(0, auth_base_1.registerAuditKind)('compliance-case.read', ['sight']);
|
|
50
|
+
const RELATIONS = ['accused', 'investigators'];
|
|
51
|
+
const text = (value) => (typeof value === 'string' && value.trim() ? value.trim() : null);
|
|
52
|
+
/** The request's person as a case sees them - asked once per request. */
|
|
53
|
+
async function caseViewerOf(context) {
|
|
54
|
+
const state = context.state;
|
|
55
|
+
state.__complianceCaseViewer ??= (async () => ({
|
|
56
|
+
userId: state.user.id,
|
|
57
|
+
handler: await (0, employee_reader_1.holds)(context, exports.CASE_CATEGORY, 'query'),
|
|
58
|
+
employeeIds: (await (0, my_employee_js_1.myEmployees)(context)).map(one => one.id)
|
|
59
|
+
}))();
|
|
60
|
+
return await state.__complianceCaseViewer;
|
|
61
|
+
}
|
|
62
|
+
/** The accounts of employees, by employee id. */
|
|
63
|
+
async function usersOfEmployees(ids, tx) {
|
|
64
|
+
if (!ids.length)
|
|
65
|
+
return new Map();
|
|
66
|
+
const employees = await (0, shell_1.getRepository)(organization_1.Employee, tx).find({ where: { id: (0, typeorm_1.In)([...ids]) } });
|
|
67
|
+
return new Map(employees.filter(one => one.userId).map(one => [one.id, one.userId]));
|
|
68
|
+
}
|
|
69
|
+
/** What the reading rule needs of a case loaded with its accused and investigators. */
|
|
70
|
+
async function factsOf(row, tx) {
|
|
71
|
+
const accusedEmployeeIds = (row.accused ?? []).map(one => one.id);
|
|
72
|
+
const users = await usersOfEmployees([...accusedEmployeeIds, ...(row.victimId ? [row.victimId] : [])], tx);
|
|
73
|
+
return {
|
|
74
|
+
reporterUserId: row.reporterUserId,
|
|
75
|
+
victimUserId: row.victimId ? users.get(row.victimId) ?? null : null,
|
|
76
|
+
accusedUserIds: accusedEmployeeIds.map(id => users.get(id)).filter(Boolean),
|
|
77
|
+
accusedEmployeeIds,
|
|
78
|
+
investigatorIds: (row.investigators ?? []).map(one => one.id),
|
|
79
|
+
noInsideHandler: row.noInsideHandler
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** The case and what the request reads of it - one answer, `null`, for "none" and "not yours". */
|
|
83
|
+
async function caseInSight(id, context, tx) {
|
|
84
|
+
const { domain } = context.state;
|
|
85
|
+
if (!id || !/^[0-9a-f-]{36}$/i.test(id))
|
|
86
|
+
return null;
|
|
87
|
+
const row = await (0, shell_1.getRepository)(compliance_case_1.ComplianceCase, tx).findOne({ where: { id, domain: { id: domain.id } }, relations: RELATIONS });
|
|
88
|
+
if (!row)
|
|
89
|
+
return null;
|
|
90
|
+
const sight = (0, compliance_case_rules_1.caseSightOf)(await factsOf(row, tx), await caseViewerOf(context));
|
|
91
|
+
return sight ? { row, sight } : null;
|
|
92
|
+
}
|
|
93
|
+
/** Writes that the request read these cases - on its own, so a failed write never holds the answer back (ADR-0141 §4-4). */
|
|
94
|
+
async function recordCaseRead(context, ids, sight) {
|
|
95
|
+
if (!ids.length)
|
|
96
|
+
return;
|
|
97
|
+
const { domain, user } = context.state;
|
|
98
|
+
await (0, auth_base_1.recordAuditAction)({ kind: 'compliance-case.read', targetKind: exports.CASE_REF_TYPE, targetIds: [...ids], targetRole: 'handled', returned: ids.length, detail: { sight } }, { actorId: user?.id ?? null, domainId: domain?.id ?? null });
|
|
99
|
+
}
|
|
100
|
+
/*
|
|
101
|
+
* ---------------------------------------------------------------- the case handlers
|
|
102
|
+
*/
|
|
103
|
+
/** The users who hold `compliance-case` in the domain - those in a role that gives it, and the domain's owners. */
|
|
104
|
+
async function caseHandlerUserIds(domain, tx) {
|
|
105
|
+
const roles = await (0, shell_1.getRepository)(auth_base_1.Role, tx)
|
|
106
|
+
.createQueryBuilder('R')
|
|
107
|
+
.innerJoin('R.privileges', 'P')
|
|
108
|
+
.leftJoinAndSelect('R.users', 'U')
|
|
109
|
+
.where('R.domain = :domain', { domain: domain.id })
|
|
110
|
+
.andWhere('P.category = :category', { category: exports.CASE_CATEGORY })
|
|
111
|
+
.getMany();
|
|
112
|
+
const ids = new Set(roles.flatMap(one => (one.users ?? []).map(user => user.id)));
|
|
113
|
+
for (const owner of await (0, auth_base_1.findDomainOwnerUserIds)(domain, tx))
|
|
114
|
+
ids.add(owner);
|
|
115
|
+
return [...ids];
|
|
116
|
+
}
|
|
117
|
+
/** Whether, with these employees reported against, a case handler is left to take it. */
|
|
118
|
+
async function insideHandlerLeft(accusedIds, context) {
|
|
119
|
+
const { domain, tx } = context.state;
|
|
120
|
+
const accusedUserIds = [...(await usersOfEmployees(accusedIds, tx)).values()];
|
|
121
|
+
return (0, compliance_case_rules_1.handlersLeft)(await caseHandlerUserIds(domain, tx), accusedUserIds).length > 0;
|
|
122
|
+
}
|
|
123
|
+
/** The investigation-start days of the domain - its setting, or seven. */
|
|
124
|
+
async function investigationDays(domain, tx) {
|
|
125
|
+
const setting = await (0, shell_1.getRepository)(setting_base_1.Setting, tx).findOne({ where: { domain: { id: domain.id }, name: compliance_case_rules_1.INVESTIGATION_DAYS_SETTING } });
|
|
126
|
+
return (0, compliance_case_rules_1.investigationDaysOf)(setting?.value);
|
|
127
|
+
}
|
|
128
|
+
/*
|
|
129
|
+
* ---------------------------------------------------------------- writing a case
|
|
130
|
+
*/
|
|
131
|
+
/** The sentences in `lng` from this module's translations, the English one where `lng` has none. */
|
|
132
|
+
const sayIn = (lng) => (key, english) => (0, translator_1.translatorFor)(lng)(key, { defaultValue: english });
|
|
133
|
+
/**
|
|
134
|
+
* The words of the notice of a new case - the same for every case: 「새 신고가 있습니다」 and nothing of it, not its
|
|
135
|
+
* kind, not a name. The handler opens the list to read it, and that read is recorded.
|
|
136
|
+
*/
|
|
137
|
+
function caseNoticeWords(lng) {
|
|
138
|
+
const say = sayIn(lng);
|
|
139
|
+
const subject = say('text.compliance-case-notice', 'There is a new report');
|
|
140
|
+
return { subject, body: subject, action: say('button.compliance-case-notice-open', 'Open'), note: '' };
|
|
141
|
+
}
|
|
142
|
+
/** Tells the handlers not reported against that there is a new case, once the request's transaction has committed. */
|
|
143
|
+
async function tellHandlers(context, userIds) {
|
|
144
|
+
const ids = userIds.filter(id => id !== context.state.user?.id);
|
|
145
|
+
if (!ids.length)
|
|
146
|
+
return;
|
|
147
|
+
const people = await (0, shell_1.getRepository)(auth_base_1.User, context.state.tx).find({ where: { id: (0, typeorm_1.In)(ids) } });
|
|
148
|
+
const receivers = people.filter(one => one.status === auth_base_1.UserStatus.ACTIVATED).map(one => ({ id: one.id, email: one.email, locale: one.locale }));
|
|
149
|
+
if (!receivers.length)
|
|
150
|
+
return;
|
|
151
|
+
const notice = { type: 'compliance-case', level: 'info', receivers, words: caseNoticeWords, address: 'compliance-case-list', label: 'compliance-case new' };
|
|
152
|
+
(0, notification_1.sendNoticeWhenCommitted)(context, notice);
|
|
153
|
+
}
|
|
154
|
+
async function employeesOf(ids, domain, tx, field) {
|
|
155
|
+
const wanted = [...new Set(ids)];
|
|
156
|
+
if (!wanted.length)
|
|
157
|
+
return [];
|
|
158
|
+
const found = await tx.getRepository(organization_1.Employee).find({ where: { id: (0, typeorm_1.In)(wanted), domain: { id: domain.id } } });
|
|
159
|
+
if (found.length !== wanted.length)
|
|
160
|
+
throw new shell_1.Refusal(`compliance-case-${field === 'accusedIds' ? 'accused' : field === 'victimId' ? 'victim' : 'reporter'}-unknown`, {}, `${field} must be employees of this domain`);
|
|
161
|
+
return found;
|
|
162
|
+
}
|
|
163
|
+
async function attach(files, refType, refBy, context) {
|
|
164
|
+
for (const file of files ?? [])
|
|
165
|
+
await (0, attachment_base_1.createAttachment)(null, { attachment: { file, refType, refBy } }, context);
|
|
166
|
+
}
|
|
167
|
+
/** Writes one case and tells the handlers left of it - the one way a case comes in, by the reporter or by a handler. */
|
|
168
|
+
async function writeCase(input, receivedOn, reporter, reporterUser, files, context) {
|
|
169
|
+
const { domain, user, tx } = context.state;
|
|
170
|
+
const refusal = (0, compliance_case_rules_1.caseReportRefusal)(input);
|
|
171
|
+
if (refusal)
|
|
172
|
+
throw refusal;
|
|
173
|
+
const accused = await employeesOf(input.accusedIds, domain, tx, 'accusedIds');
|
|
174
|
+
const [victim] = input.victimId ? await employeesOf([input.victimId], domain, tx, 'victimId') : [null];
|
|
175
|
+
const accusedUserIds = accused.map(one => one.userId).filter(Boolean);
|
|
176
|
+
const left = (0, compliance_case_rules_1.handlersLeft)(await caseHandlerUserIds(domain, tx), accusedUserIds);
|
|
177
|
+
const repository = tx.getRepository(compliance_case_1.ComplianceCase);
|
|
178
|
+
const saved = await repository.save(repository.create({
|
|
179
|
+
domain,
|
|
180
|
+
kind: input.kind,
|
|
181
|
+
reporter,
|
|
182
|
+
reporterUser,
|
|
183
|
+
victim,
|
|
184
|
+
accused,
|
|
185
|
+
occurredOn: text(input.occurredOn),
|
|
186
|
+
description: input.description.trim(),
|
|
187
|
+
receivedOn,
|
|
188
|
+
investigationDueOn: (0, compliance_case_rules_1.dayPlus)(receivedOn, await investigationDays(domain, tx)),
|
|
189
|
+
noInsideHandler: left.length === 0,
|
|
190
|
+
investigators: [],
|
|
191
|
+
status: compliance_case_1.ComplianceCaseStatus.RECEIVED,
|
|
192
|
+
creator: user,
|
|
193
|
+
updater: user
|
|
194
|
+
}));
|
|
195
|
+
await attach(files, exports.CASE_REF_TYPE, saved.id, context);
|
|
196
|
+
if (!saved.noInsideHandler)
|
|
197
|
+
await tellHandlers(context, left);
|
|
198
|
+
return saved;
|
|
199
|
+
}
|
|
200
|
+
/** An employee reports a case of their own seeing - a partner, or an account with no employee record, is refused. */
|
|
201
|
+
async function reportComplianceCase(input, files, context) {
|
|
202
|
+
const { domain, user, tx } = context.state;
|
|
203
|
+
const me = await (0, employee_reader_1.requireWorkingEmployee)(context);
|
|
204
|
+
const saved = await writeCase(input, (0, employee_reader_1.todayIn)(domain), me, user, files, context);
|
|
205
|
+
const row = await tx.getRepository(compliance_case_1.ComplianceCase).findOne({ where: { id: saved.id }, relations: RELATIONS });
|
|
206
|
+
return await reportViewOf(row, 'REPORTER', context, tx);
|
|
207
|
+
}
|
|
208
|
+
/** A handler writes down a report received another way - by mouth, by mail. One reported against is not its handler. */
|
|
209
|
+
async function recordComplianceCase(input, files, context) {
|
|
210
|
+
const { domain, tx } = context.state;
|
|
211
|
+
if (!input.receivedOn || !/^\d{4}-\d{2}-\d{2}$/.test(input.receivedOn))
|
|
212
|
+
throw new shell_1.Refusal('compliance-case-received-on-invalid', {}, 'give the day it was received as YYYY-MM-DD');
|
|
213
|
+
const viewer = await caseViewerOf(context);
|
|
214
|
+
if (viewer.employeeIds.some(id => input.accusedIds?.includes(id)))
|
|
215
|
+
throw new shell_1.Refusal('compliance-case-accused-may-not-handle', {}, 'one reported against does not write the case');
|
|
216
|
+
const [reporter] = input.reporterId ? await employeesOf([input.reporterId], domain, tx, 'reporterId') : [null];
|
|
217
|
+
const reporterUser = reporter?.userId ? await tx.getRepository(auth_base_1.User).findOne({ where: { id: reporter.userId } }) : null;
|
|
218
|
+
const saved = await writeCase(input, input.receivedOn, reporter, reporterUser, files, context);
|
|
219
|
+
return (await tx.getRepository(compliance_case_1.ComplianceCase).findOne({ where: { id: saved.id }, relations: RELATIONS }));
|
|
220
|
+
}
|
|
221
|
+
/** The case as one who reads all of it, or refused - one answer for "none", "not yours" and "reported against". */
|
|
222
|
+
async function fullCase(id, context, tx) {
|
|
223
|
+
const found = await caseInSight(id, context, tx);
|
|
224
|
+
if (!found || found.sight !== 'FULL')
|
|
225
|
+
throw new shell_1.Refusal('compliance-case-not-found', {}, 'the case was not found. reload and try again.');
|
|
226
|
+
return found.row;
|
|
227
|
+
}
|
|
228
|
+
/** What the handler writes on a case as it goes. A value already written changes with a correction kept. */
|
|
229
|
+
async function handleComplianceCase(patch, context) {
|
|
230
|
+
const { domain, user, tx } = context.state;
|
|
231
|
+
const row = await fullCase(patch.id, context, tx);
|
|
232
|
+
const values = {};
|
|
233
|
+
for (const field of compliance_case_rules_1.HANDLING_FIELDS)
|
|
234
|
+
if (patch[field] !== undefined)
|
|
235
|
+
values[field] = text(patch[field]);
|
|
236
|
+
const refusal = (0, compliance_case_rules_1.caseHandlingRefusal)(values, row);
|
|
237
|
+
if (refusal)
|
|
238
|
+
throw refusal;
|
|
239
|
+
const before = { ...row, investigatorIds: (row.investigators ?? []).map(one => one.id).sort().join(',') };
|
|
240
|
+
if (patch.investigatorIds) {
|
|
241
|
+
const wanted = [...new Set(patch.investigatorIds)];
|
|
242
|
+
const people = wanted.length ? await (0, auth_base_1.buildDomainUsersQueryBuilder)(domain.id, 'USER', tx).andWhere('USER.id IN (:...ids)', { ids: wanted }).getMany() : [];
|
|
243
|
+
if (people.length !== wanted.length)
|
|
244
|
+
throw new shell_1.Refusal('compliance-case-investigator-unknown', {}, 'an investigator must be a user of this domain');
|
|
245
|
+
const facts = await factsOf(row, tx);
|
|
246
|
+
if (people.some(one => facts.accusedUserIds.includes(one.id)))
|
|
247
|
+
throw new shell_1.Refusal('compliance-case-investigator-accused', {}, 'one reported against does not investigate the case');
|
|
248
|
+
row.investigators = people;
|
|
249
|
+
}
|
|
250
|
+
Object.assign(row, values);
|
|
251
|
+
const after = { ...values, ...(patch.investigatorIds ? { investigatorIds: (row.investigators ?? []).map(one => one.id).sort().join(',') } : {}) };
|
|
252
|
+
await (0, correction_1.recordCorrections)(tx, domain, user, { kind: exports.CASE_REF_TYPE, id: row.id }, before, after, [...compliance_case_rules_1.HANDLING_FIELDS, 'investigatorIds']);
|
|
253
|
+
row.status = (0, compliance_case_rules_1.caseStatusOf)(row);
|
|
254
|
+
row.updater = user;
|
|
255
|
+
return await tx.getRepository(compliance_case_1.ComplianceCase).save(row);
|
|
256
|
+
}
|
|
257
|
+
/** One entry of the investigation record - written once, never changed. */
|
|
258
|
+
async function addComplianceCaseEntry(caseId, writtenOn, body, files, context) {
|
|
259
|
+
const { domain, user, tx } = context.state;
|
|
260
|
+
const row = await fullCase(caseId, context, tx);
|
|
261
|
+
if (row.closedOn)
|
|
262
|
+
throw new shell_1.Refusal('compliance-case-closed', {}, 'a closed case is not written on');
|
|
263
|
+
if (!writtenOn || !/^\d{4}-\d{2}-\d{2}$/.test(writtenOn))
|
|
264
|
+
throw new shell_1.Refusal('compliance-case-written-on-invalid', {}, 'give the day as YYYY-MM-DD');
|
|
265
|
+
if (!body?.trim())
|
|
266
|
+
throw new shell_1.Refusal('compliance-case-entry-required', {}, 'write what the entry records');
|
|
267
|
+
const repository = tx.getRepository(compliance_case_1.ComplianceCaseEntry);
|
|
268
|
+
const saved = await repository.save(repository.create({ domain, complianceCase: row, writtenOn, body: body.trim(), creator: user }));
|
|
269
|
+
await attach(files, exports.CASE_ENTRY_REF_TYPE, saved.id, context);
|
|
270
|
+
return saved;
|
|
271
|
+
}
|
|
272
|
+
/*
|
|
273
|
+
* ---------------------------------------------------------------- reading cases
|
|
274
|
+
*/
|
|
275
|
+
/** The cases the handler reads, a page of them - never one they are reported against, never one left to the reporter. */
|
|
276
|
+
async function complianceCasesFor(params, context) {
|
|
277
|
+
const { domain } = context.state;
|
|
278
|
+
const viewer = await caseViewerOf(context);
|
|
279
|
+
const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
|
|
280
|
+
domain,
|
|
281
|
+
params,
|
|
282
|
+
repository: (0, shell_1.getRepository)(compliance_case_1.ComplianceCase),
|
|
283
|
+
searchables: [],
|
|
284
|
+
alias: 'cc',
|
|
285
|
+
defaultSortings: [{ name: 'receivedOn', desc: true }]
|
|
286
|
+
});
|
|
287
|
+
queryBuilder.andWhere('cc.noInsideHandler = :none', { none: false });
|
|
288
|
+
if (viewer.employeeIds.length) {
|
|
289
|
+
const against = (0, shell_1.getRepository)(compliance_case_1.ComplianceCase)
|
|
290
|
+
.createQueryBuilder('ac')
|
|
291
|
+
.select('ac.id')
|
|
292
|
+
.innerJoin('ac.accused', 'accused')
|
|
293
|
+
.where('accused.id IN (:...mine)');
|
|
294
|
+
queryBuilder.andWhere(`cc.id NOT IN (${against.getQuery()})`, { mine: viewer.employeeIds });
|
|
295
|
+
}
|
|
296
|
+
if (!viewer.handler)
|
|
297
|
+
queryBuilder.andWhere('1 = 0');
|
|
298
|
+
const [items, total] = await queryBuilder.getManyAndCount();
|
|
299
|
+
await recordCaseRead(context, items.map(one => one.id), 'FULL');
|
|
300
|
+
return { items, total };
|
|
301
|
+
}
|
|
302
|
+
/** The cases the request investigates - for an investigator who is no handler, an outside labour attorney. */
|
|
303
|
+
async function myInvestigations(context) {
|
|
304
|
+
const { domain, user } = context.state;
|
|
305
|
+
const rows = await (0, shell_1.getRepository)(compliance_case_1.ComplianceCase)
|
|
306
|
+
.createQueryBuilder('cc')
|
|
307
|
+
.innerJoin('cc.investigators', 'investigator', 'investigator.id = :me', { me: user.id })
|
|
308
|
+
.where('cc.domain = :domain', { domain: domain.id })
|
|
309
|
+
.orderBy('cc.receivedOn', 'DESC')
|
|
310
|
+
.getMany();
|
|
311
|
+
const viewer = await caseViewerOf(context);
|
|
312
|
+
const kept = [];
|
|
313
|
+
for (const one of rows) {
|
|
314
|
+
const full = await (0, shell_1.getRepository)(compliance_case_1.ComplianceCase).findOne({ where: { id: one.id }, relations: RELATIONS });
|
|
315
|
+
if (full && (0, compliance_case_rules_1.caseSightOf)(await factsOf(full), viewer) === 'FULL')
|
|
316
|
+
kept.push(full);
|
|
317
|
+
}
|
|
318
|
+
await recordCaseRead(context, kept.map(one => one.id), 'FULL');
|
|
319
|
+
return kept;
|
|
320
|
+
}
|
|
321
|
+
/** One case, whole - for its handlers and investigators. */
|
|
322
|
+
async function complianceCaseFor(id, context) {
|
|
323
|
+
const row = await fullCase(id, context, context.state.tx);
|
|
324
|
+
await recordCaseRead(context, [row.id], 'FULL');
|
|
325
|
+
return row;
|
|
326
|
+
}
|
|
327
|
+
/** A case as the reporter or the victim reads it - what they may, and no field of the investigation. */
|
|
328
|
+
async function reportViewOf(row, standing, context, tx) {
|
|
329
|
+
const reporter = standing === 'REPORTER';
|
|
330
|
+
const victim = reporter && row.victimId ? await (0, shell_1.getRepository)(organization_1.Employee, tx).findOne({ where: { id: row.victimId } }) : null;
|
|
331
|
+
const files = reporter
|
|
332
|
+
? await (0, shell_1.getRepository)(attachment_base_1.Attachment, tx).find({ where: { domain: { id: context.state.domain.id }, refType: exports.CASE_REF_TYPE, refBy: row.id, creator: { id: context.state.user.id } } })
|
|
333
|
+
: [];
|
|
334
|
+
return {
|
|
335
|
+
id: row.id,
|
|
336
|
+
kind: row.kind,
|
|
337
|
+
status: row.status,
|
|
338
|
+
standing,
|
|
339
|
+
receivedOn: row.receivedOn,
|
|
340
|
+
noInsideHandler: row.noInsideHandler,
|
|
341
|
+
...(reporter ? { occurredOn: row.occurredOn, description: row.description, accusedNames: (row.accused ?? []).map(one => one.name), victimName: victim?.name, attachments: files } : {}),
|
|
342
|
+
protectionMeasures: row.protectionMeasures,
|
|
343
|
+
victimOpinion: row.victimOpinion,
|
|
344
|
+
resultNotice: row.resultToldOn ? row.resultNotice : null,
|
|
345
|
+
resultToldOn: row.resultToldOn,
|
|
346
|
+
closedOn: row.closedOn
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
/** The cases the request reported, or that happened to them - each as a party reads it. */
|
|
350
|
+
async function myComplianceReports(context) {
|
|
351
|
+
const { domain, user } = context.state;
|
|
352
|
+
const viewer = await caseViewerOf(context);
|
|
353
|
+
const queryBuilder = (0, shell_1.getRepository)(compliance_case_1.ComplianceCase).createQueryBuilder('cc').where('cc.domain = :domain', { domain: domain.id });
|
|
354
|
+
if (viewer.employeeIds.length)
|
|
355
|
+
queryBuilder.andWhere('(cc.reporterUser = :me OR cc.victim IN (:...mine))', { me: user.id, mine: viewer.employeeIds });
|
|
356
|
+
else
|
|
357
|
+
queryBuilder.andWhere('cc.reporterUser = :me', { me: user.id });
|
|
358
|
+
const rows = await queryBuilder.orderBy('cc.receivedOn', 'DESC').getMany();
|
|
359
|
+
const views = [];
|
|
360
|
+
for (const one of rows) {
|
|
361
|
+
const row = await (0, shell_1.getRepository)(compliance_case_1.ComplianceCase).findOne({ where: { id: one.id }, relations: RELATIONS });
|
|
362
|
+
const facts = await factsOf(row);
|
|
363
|
+
/* The party view, whatever more the reader may read on the handlers' side. */
|
|
364
|
+
const party = (0, compliance_case_rules_1.caseSightOf)(facts, { ...viewer, handler: false });
|
|
365
|
+
if (party)
|
|
366
|
+
views.push(await reportViewOf(row, facts.reporterUserId === user.id ? 'REPORTER' : 'VICTIM', context));
|
|
367
|
+
}
|
|
368
|
+
await recordCaseRead(context, views.map(one => one.id), 'PARTY');
|
|
369
|
+
return views;
|
|
370
|
+
}
|
|
371
|
+
/** The employees still working here a reporter may name, found by name - for a working employee only. */
|
|
372
|
+
async function casePeople(words, context) {
|
|
373
|
+
const { domain } = context.state;
|
|
374
|
+
await (0, employee_reader_1.requireWorkingEmployee)(context);
|
|
375
|
+
const wanted = (words ?? '').trim().toLowerCase();
|
|
376
|
+
if (!wanted)
|
|
377
|
+
return [];
|
|
378
|
+
const today = (0, employee_reader_1.todayIn)(domain);
|
|
379
|
+
const employees = await (0, shell_1.getRepository)(organization_1.Employee).find({ where: { domain: { id: domain.id } }, order: { name: 'ASC' } });
|
|
380
|
+
return employees
|
|
381
|
+
.filter(one => one.active !== false && (!one.retiredOn || one.retiredOn > today) && one.name?.toLowerCase().includes(wanted))
|
|
382
|
+
.slice(0, 20)
|
|
383
|
+
.map(one => ({ id: one.id, name: one.name, note: one.controlNo }));
|
|
384
|
+
}
|
|
385
|
+
/** The users of the domain a handler may name as investigators, found by name or mail. */
|
|
386
|
+
async function investigatorChoices(words, context) {
|
|
387
|
+
const wanted = (words ?? '').trim().toLowerCase();
|
|
388
|
+
if (!wanted)
|
|
389
|
+
return [];
|
|
390
|
+
return (await (0, auth_base_1.getDomainAssignees)(context.state.domain))
|
|
391
|
+
.filter(one => `${one.name ?? ''} ${one.email ?? ''}`.toLowerCase().includes(wanted))
|
|
392
|
+
.slice(0, 20)
|
|
393
|
+
.map(one => ({ id: one.id, name: one.name || one.email, note: one.email }));
|
|
394
|
+
}
|
|
395
|
+
/*
|
|
396
|
+
* ---------------------------------------------------------------- files
|
|
397
|
+
*/
|
|
398
|
+
/**
|
|
399
|
+
* Who opens a file of a case. The report's files: those who read all of it, and the reporter their own. The
|
|
400
|
+
* investigation's files: those who read all of it. Every opening is a read of the case, recorded.
|
|
401
|
+
*/
|
|
402
|
+
async function mayReadCaseFile(attachment, context) {
|
|
403
|
+
const entry = attachment.refType === exports.CASE_ENTRY_REF_TYPE;
|
|
404
|
+
const caseId = entry ? (await (0, shell_1.getRepository)(compliance_case_1.ComplianceCaseEntry).findOne({ where: { id: attachment.refBy } }))?.complianceCaseId : attachment.refBy;
|
|
405
|
+
const found = caseId ? await caseInSight(caseId, context) : null;
|
|
406
|
+
if (!found)
|
|
407
|
+
return false;
|
|
408
|
+
const allowed = found.sight === 'FULL' || (!entry && found.row.reporterUserId === context.state.user.id && attachment.creatorId === context.state.user.id);
|
|
409
|
+
if (allowed)
|
|
410
|
+
await recordCaseRead(context, [found.row.id], found.sight);
|
|
411
|
+
return allowed;
|
|
412
|
+
}
|
|
413
|
+
/*
|
|
414
|
+
* ---------------------------------------------------------------- the management check (ADR-0146)
|
|
415
|
+
*/
|
|
416
|
+
/**
|
|
417
|
+
* Cases past their investigation-start day with no investigation started (decision 21). Only the day and the count -
|
|
418
|
+
* a check is read by more than the case handlers, so nothing of a case is in it. A case left to the reporter alone,
|
|
419
|
+
* with nobody inside to investigate it, is not on it.
|
|
420
|
+
*/
|
|
421
|
+
async function complianceCasesNotInvestigated(tx, domain, today) {
|
|
422
|
+
const open = await tx.getRepository(compliance_case_1.ComplianceCase).find({ where: { domain: { id: domain.id }, noInsideHandler: false }, order: { receivedOn: 'ASC' } });
|
|
423
|
+
return open.filter(one => (0, compliance_case_rules_1.investigationLate)(one, today)).map(one => ({ id: one.id, receivedOn: one.receivedOn, investigationDueOn: one.investigationDueOn }));
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=compliance-case-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance-case-service.js","sourceRoot":"","sources":["../../../server/service/compliance-case/compliance-case-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In } from 'typeorm'\n\nimport { Attachment, createAttachment } from '@things-factory/attachment-base'\nimport { buildDomainUsersQueryBuilder, findDomainOwnerUserIds, getDomainAssignees, recordAuditAction, registerAuditKind, Role, User, UserStatus } from '@things-factory/auth-base'\nimport { translatorFor } from '@things-factory/i18n-base/translator'\nimport { sendNoticeWhenCommitted, type Notice } from '@things-factory/notification'\nimport { Employee } from '@things-factory/organization'\nimport { myEmployees } from '@things-factory/organization/dist-server/service/employee/my-employee.js'\nimport { Setting } from '@things-factory/setting-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, Refusal } from '@things-factory/shell'\n\nimport { recordCorrections } from '../common/correction'\nimport { holds, requireWorkingEmployee, todayIn } from '../common/employee-reader'\nimport { ComplianceCase, ComplianceCaseEntry, ComplianceCaseStatus } from './compliance-case'\nimport {\n caseHandlingRefusal,\n caseReportRefusal,\n CaseFacts,\n CaseSight,\n caseSightOf,\n caseStatusOf,\n CaseViewer,\n dayPlus,\n HANDLING_FIELDS,\n handlersLeft,\n INVESTIGATION_DAYS_SETTING,\n investigationDaysOf,\n investigationLate\n} from './compliance-case-rules'\nimport { ComplianceCaseHandling, ComplianceCasePerson, ComplianceReportView, NewComplianceCase, NewComplianceCaseReport } from './compliance-case-type'\n\n/*\n * 신고 사건 (ADR-0187 decision 21) and the database. Every door that hands out a case - a list, one case, a file - asks\n * `caseSightOf` here on the server and writes the read to the audit record (ADR-0141 §3.3: the service records the\n * targets it handled). Nothing of a case is registered for AI reading or search, and the notice of a new one carries\n * no word of it.\n */\n\n/** The files of a report hang on the case under this `refType`, those of the investigation on its entries (attachment-base). */\nexport const CASE_REF_TYPE = 'ComplianceCase'\nexport const CASE_ENTRY_REF_TYPE = 'ComplianceCaseEntry'\n/** The privilege category of the case handlers (`compliance.case-handling`). */\nexport const CASE_CATEGORY = 'compliance-case'\n\n/* A read of a case is an event of its own; `sight` says how much was read - FULL or PARTY. */\nregisterAuditKind('compliance-case.read', ['sight'])\n\nconst RELATIONS = ['accused', 'investigators']\nconst text = (value: unknown) => (typeof value === 'string' && value.trim() ? value.trim() : null)\n\n/** The request's person as a case sees them - asked once per request. */\nexport async function caseViewerOf(context: any): Promise<CaseViewer> {\n const state = context.state\n state.__complianceCaseViewer ??= (async () => ({\n userId: state.user.id,\n handler: await holds(context, CASE_CATEGORY, 'query'),\n employeeIds: (await myEmployees(context)).map(one => one.id)\n }))()\n return await state.__complianceCaseViewer\n}\n\n/** The accounts of employees, by employee id. */\nasync function usersOfEmployees(ids: readonly string[], tx?: EntityManager): Promise<Map<string, string>> {\n if (!ids.length) return new Map()\n const employees = await getRepository(Employee, tx).find({ where: { id: In([...ids]) } as any })\n return new Map(employees.filter(one => one.userId).map(one => [one.id, one.userId!]))\n}\n\n/** What the reading rule needs of a case loaded with its accused and investigators. */\nexport async function factsOf(row: ComplianceCase, tx?: EntityManager): Promise<CaseFacts> {\n const accusedEmployeeIds = (row.accused ?? []).map(one => one.id)\n const users = await usersOfEmployees([...accusedEmployeeIds, ...(row.victimId ? [row.victimId] : [])], tx)\n return {\n reporterUserId: row.reporterUserId,\n victimUserId: row.victimId ? users.get(row.victimId) ?? null : null,\n accusedUserIds: accusedEmployeeIds.map(id => users.get(id)).filter(Boolean) as string[],\n accusedEmployeeIds,\n investigatorIds: (row.investigators ?? []).map(one => one.id),\n noInsideHandler: row.noInsideHandler\n }\n}\n\n/** The case and what the request reads of it - one answer, `null`, for \"none\" and \"not yours\". */\nexport async function caseInSight(id: string, context: any, tx?: EntityManager): Promise<{ row: ComplianceCase; sight: CaseSight } | null> {\n const { domain } = context.state\n if (!id || !/^[0-9a-f-]{36}$/i.test(id)) return null\n const row = await getRepository(ComplianceCase, tx).findOne({ where: { id, domain: { id: domain.id } } as any, relations: RELATIONS })\n if (!row) return null\n const sight = caseSightOf(await factsOf(row, tx), await caseViewerOf(context))\n return sight ? { row, sight } : null\n}\n\n/** Writes that the request read these cases - on its own, so a failed write never holds the answer back (ADR-0141 §4-4). */\nexport async function recordCaseRead(context: any, ids: readonly string[], sight: 'FULL' | 'PARTY'): Promise<void> {\n if (!ids.length) return\n const { domain, user } = context.state\n await recordAuditAction(\n { kind: 'compliance-case.read', targetKind: CASE_REF_TYPE, targetIds: [...ids], targetRole: 'handled', returned: ids.length, detail: { sight } },\n { actorId: user?.id ?? null, domainId: domain?.id ?? null }\n )\n}\n\n/*\n * ---------------------------------------------------------------- the case handlers\n */\n\n/** The users who hold `compliance-case` in the domain - those in a role that gives it, and the domain's owners. */\nexport async function caseHandlerUserIds(domain: Domain, tx?: EntityManager): Promise<string[]> {\n const roles = await getRepository(Role, tx)\n .createQueryBuilder('R')\n .innerJoin('R.privileges', 'P')\n .leftJoinAndSelect('R.users', 'U')\n .where('R.domain = :domain', { domain: domain.id })\n .andWhere('P.category = :category', { category: CASE_CATEGORY })\n .getMany()\n const ids = new Set<string>(roles.flatMap(one => (one.users ?? []).map(user => user.id)))\n for (const owner of await findDomainOwnerUserIds(domain, tx)) ids.add(owner)\n return [...ids]\n}\n\n/** Whether, with these employees reported against, a case handler is left to take it. */\nexport async function insideHandlerLeft(accusedIds: readonly string[], context: any): Promise<boolean> {\n const { domain, tx } = context.state\n const accusedUserIds = [...(await usersOfEmployees(accusedIds, tx)).values()]\n return handlersLeft(await caseHandlerUserIds(domain, tx), accusedUserIds).length > 0\n}\n\n/** The investigation-start days of the domain - its setting, or seven. */\nexport async function investigationDays(domain: Domain, tx?: EntityManager): Promise<number> {\n const setting = await getRepository(Setting, tx).findOne({ where: { domain: { id: domain.id }, name: INVESTIGATION_DAYS_SETTING } as any })\n return investigationDaysOf(setting?.value)\n}\n\n/*\n * ---------------------------------------------------------------- writing a case\n */\n\n/** The sentences in `lng` from this module's translations, the English one where `lng` has none. */\nconst sayIn = (lng: string) => (key: string, english: string) => translatorFor(lng)(key, { defaultValue: english })\n\n/**\n * The words of the notice of a new case - the same for every case: 「새 신고가 있습니다」 and nothing of it, not its\n * kind, not a name. The handler opens the list to read it, and that read is recorded.\n */\nexport function caseNoticeWords(lng: string) {\n const say = sayIn(lng)\n const subject = say('text.compliance-case-notice', 'There is a new report')\n return { subject, body: subject, action: say('button.compliance-case-notice-open', 'Open'), note: '' }\n}\n\n/** Tells the handlers not reported against that there is a new case, once the request's transaction has committed. */\nasync function tellHandlers(context: any, userIds: string[]): Promise<void> {\n const ids = userIds.filter(id => id !== context.state.user?.id)\n if (!ids.length) return\n const people = await getRepository(User, context.state.tx).find({ where: { id: In(ids) } as any })\n const receivers = people.filter(one => one.status === UserStatus.ACTIVATED).map(one => ({ id: one.id, email: one.email, locale: (one as any).locale }))\n if (!receivers.length) return\n const notice: Notice = { type: 'compliance-case', level: 'info', receivers, words: caseNoticeWords, address: 'compliance-case-list', label: 'compliance-case new' }\n sendNoticeWhenCommitted(context, notice)\n}\n\nasync function employeesOf(ids: readonly string[], domain: Domain, tx: EntityManager, field: string): Promise<Employee[]> {\n const wanted = [...new Set(ids)]\n if (!wanted.length) return []\n const found = await tx.getRepository(Employee).find({ where: { id: In(wanted), domain: { id: domain.id } } as any })\n if (found.length !== wanted.length) throw new Refusal(`compliance-case-${field === 'accusedIds' ? 'accused' : field === 'victimId' ? 'victim' : 'reporter'}-unknown`, {}, `${field} must be employees of this domain`)\n return found\n}\n\nasync function attach(files: any[] | undefined, refType: string, refBy: string, context: any) {\n for (const file of files ?? []) await createAttachment(null, { attachment: { file, refType, refBy } } as any, context)\n}\n\n/** Writes one case and tells the handlers left of it - the one way a case comes in, by the reporter or by a handler. */\nasync function writeCase(input: NewComplianceCaseReport, receivedOn: string, reporter: Employee | null, reporterUser: User | null, files: any[] | undefined, context: any): Promise<ComplianceCase> {\n const { domain, user, tx } = context.state\n const refusal = caseReportRefusal(input)\n if (refusal) throw refusal\n const accused = await employeesOf(input.accusedIds, domain, tx, 'accusedIds')\n const [victim] = input.victimId ? await employeesOf([input.victimId], domain, tx, 'victimId') : [null]\n const accusedUserIds = accused.map(one => one.userId).filter(Boolean) as string[]\n const left = handlersLeft(await caseHandlerUserIds(domain, tx), accusedUserIds)\n\n const repository = tx.getRepository(ComplianceCase)\n const saved = await repository.save(\n repository.create({\n domain,\n kind: input.kind,\n reporter,\n reporterUser,\n victim,\n accused,\n occurredOn: text(input.occurredOn),\n description: input.description.trim(),\n receivedOn,\n investigationDueOn: dayPlus(receivedOn, await investigationDays(domain, tx)),\n noInsideHandler: left.length === 0,\n investigators: [],\n status: ComplianceCaseStatus.RECEIVED,\n creator: user,\n updater: user\n } as any) as unknown as ComplianceCase\n )\n await attach(files, CASE_REF_TYPE, saved.id, context)\n if (!saved.noInsideHandler) await tellHandlers(context, left)\n return saved\n}\n\n/** An employee reports a case of their own seeing - a partner, or an account with no employee record, is refused. */\nexport async function reportComplianceCase(input: NewComplianceCaseReport, files: any[] | undefined, context: any): Promise<ComplianceReportView> {\n const { domain, user, tx } = context.state\n const me = await requireWorkingEmployee(context)\n const saved = await writeCase(input, todayIn(domain), me, user, files, context)\n const row = await tx.getRepository(ComplianceCase).findOne({ where: { id: saved.id } as any, relations: RELATIONS })\n return await reportViewOf(row, 'REPORTER', context, tx)\n}\n\n/** A handler writes down a report received another way - by mouth, by mail. One reported against is not its handler. */\nexport async function recordComplianceCase(input: NewComplianceCase, files: any[] | undefined, context: any): Promise<ComplianceCase> {\n const { domain, tx } = context.state\n if (!input.receivedOn || !/^\\d{4}-\\d{2}-\\d{2}$/.test(input.receivedOn)) throw new Refusal('compliance-case-received-on-invalid', {}, 'give the day it was received as YYYY-MM-DD')\n const viewer = await caseViewerOf(context)\n if (viewer.employeeIds.some(id => input.accusedIds?.includes(id))) throw new Refusal('compliance-case-accused-may-not-handle', {}, 'one reported against does not write the case')\n const [reporter] = input.reporterId ? await employeesOf([input.reporterId], domain, tx, 'reporterId') : [null]\n const reporterUser = reporter?.userId ? await tx.getRepository(User).findOne({ where: { id: reporter.userId } as any }) : null\n const saved = await writeCase(input, input.receivedOn, reporter, reporterUser, files, context)\n return (await tx.getRepository(ComplianceCase).findOne({ where: { id: saved.id } as any, relations: RELATIONS }))!\n}\n\n/** The case as one who reads all of it, or refused - one answer for \"none\", \"not yours\" and \"reported against\". */\nasync function fullCase(id: string, context: any, tx: EntityManager): Promise<ComplianceCase> {\n const found = await caseInSight(id, context, tx)\n if (!found || found.sight !== 'FULL') throw new Refusal('compliance-case-not-found', {}, 'the case was not found. reload and try again.')\n return found.row\n}\n\n/** What the handler writes on a case as it goes. A value already written changes with a correction kept. */\nexport async function handleComplianceCase(patch: ComplianceCaseHandling, context: any): Promise<ComplianceCase> {\n const { domain, user, tx } = context.state\n const row = await fullCase(patch.id, context, tx)\n const values: Record<string, any> = {}\n for (const field of HANDLING_FIELDS) if ((patch as any)[field] !== undefined) values[field] = text((patch as any)[field])\n const refusal = caseHandlingRefusal(values, row as any)\n if (refusal) throw refusal\n\n const before: Record<string, any> = { ...row, investigatorIds: (row.investigators ?? []).map(one => one.id).sort().join(',') }\n if (patch.investigatorIds) {\n const wanted = [...new Set(patch.investigatorIds)]\n const people = wanted.length ? await buildDomainUsersQueryBuilder(domain.id, 'USER', tx).andWhere('USER.id IN (:...ids)', { ids: wanted }).getMany() : []\n if (people.length !== wanted.length) throw new Refusal('compliance-case-investigator-unknown', {}, 'an investigator must be a user of this domain')\n const facts = await factsOf(row, tx)\n if (people.some(one => facts.accusedUserIds.includes(one.id))) throw new Refusal('compliance-case-investigator-accused', {}, 'one reported against does not investigate the case')\n row.investigators = people\n }\n Object.assign(row, values)\n const after = { ...values, ...(patch.investigatorIds ? { investigatorIds: (row.investigators ?? []).map(one => one.id).sort().join(',') } : {}) }\n await recordCorrections(tx, domain, user, { kind: CASE_REF_TYPE, id: row.id }, before, after, [...HANDLING_FIELDS, 'investigatorIds'])\n row.status = caseStatusOf(row) as ComplianceCaseStatus\n row.updater = user\n return await tx.getRepository(ComplianceCase).save(row)\n}\n\n/** One entry of the investigation record - written once, never changed. */\nexport async function addComplianceCaseEntry(caseId: string, writtenOn: string, body: string, files: any[] | undefined, context: any): Promise<ComplianceCaseEntry> {\n const { domain, user, tx } = context.state\n const row = await fullCase(caseId, context, tx)\n if (row.closedOn) throw new Refusal('compliance-case-closed', {}, 'a closed case is not written on')\n if (!writtenOn || !/^\\d{4}-\\d{2}-\\d{2}$/.test(writtenOn)) throw new Refusal('compliance-case-written-on-invalid', {}, 'give the day as YYYY-MM-DD')\n if (!body?.trim()) throw new Refusal('compliance-case-entry-required', {}, 'write what the entry records')\n const repository = tx.getRepository(ComplianceCaseEntry)\n const saved = await repository.save(repository.create({ domain, complianceCase: row, writtenOn, body: body.trim(), creator: user } as any) as unknown as ComplianceCaseEntry)\n await attach(files, CASE_ENTRY_REF_TYPE, saved.id, context)\n return saved\n}\n\n/*\n * ---------------------------------------------------------------- reading cases\n */\n\n/** The cases the handler reads, a page of them - never one they are reported against, never one left to the reporter. */\nexport async function complianceCasesFor(params: ListParam, context: any): Promise<{ items: ComplianceCase[]; total: number }> {\n const { domain } = context.state\n const viewer = await caseViewerOf(context)\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: getRepository(ComplianceCase),\n searchables: [],\n alias: 'cc',\n defaultSortings: [{ name: 'receivedOn', desc: true }]\n })\n queryBuilder.andWhere('cc.noInsideHandler = :none', { none: false })\n if (viewer.employeeIds.length) {\n const against = getRepository(ComplianceCase)\n .createQueryBuilder('ac')\n .select('ac.id')\n .innerJoin('ac.accused', 'accused')\n .where('accused.id IN (:...mine)')\n queryBuilder.andWhere(`cc.id NOT IN (${against.getQuery()})`, { mine: viewer.employeeIds })\n }\n if (!viewer.handler) queryBuilder.andWhere('1 = 0')\n const [items, total] = await queryBuilder.getManyAndCount()\n await recordCaseRead(context, items.map(one => one.id), 'FULL')\n return { items, total }\n}\n\n/** The cases the request investigates - for an investigator who is no handler, an outside labour attorney. */\nexport async function myInvestigations(context: any): Promise<ComplianceCase[]> {\n const { domain, user } = context.state\n const rows = await getRepository(ComplianceCase)\n .createQueryBuilder('cc')\n .innerJoin('cc.investigators', 'investigator', 'investigator.id = :me', { me: user.id })\n .where('cc.domain = :domain', { domain: domain.id })\n .orderBy('cc.receivedOn', 'DESC')\n .getMany()\n const viewer = await caseViewerOf(context)\n const kept: ComplianceCase[] = []\n for (const one of rows) {\n const full = await getRepository(ComplianceCase).findOne({ where: { id: one.id } as any, relations: RELATIONS })\n if (full && caseSightOf(await factsOf(full), viewer) === 'FULL') kept.push(full)\n }\n await recordCaseRead(context, kept.map(one => one.id), 'FULL')\n return kept\n}\n\n/** One case, whole - for its handlers and investigators. */\nexport async function complianceCaseFor(id: string, context: any): Promise<ComplianceCase> {\n const row = await fullCase(id, context, context.state.tx)\n await recordCaseRead(context, [row.id], 'FULL')\n return row\n}\n\n/** A case as the reporter or the victim reads it - what they may, and no field of the investigation. */\nasync function reportViewOf(row: ComplianceCase, standing: 'REPORTER' | 'VICTIM', context: any, tx?: EntityManager): Promise<ComplianceReportView> {\n const reporter = standing === 'REPORTER'\n const victim = reporter && row.victimId ? await getRepository(Employee, tx).findOne({ where: { id: row.victimId } as any }) : null\n const files = reporter\n ? await getRepository(Attachment, tx).find({ where: { domain: { id: context.state.domain.id }, refType: CASE_REF_TYPE, refBy: row.id, creator: { id: context.state.user.id } } as any })\n : []\n return {\n id: row.id,\n kind: row.kind,\n status: row.status,\n standing,\n receivedOn: row.receivedOn,\n noInsideHandler: row.noInsideHandler,\n ...(reporter ? { occurredOn: row.occurredOn, description: row.description, accusedNames: (row.accused ?? []).map(one => one.name), victimName: victim?.name, attachments: files } : {}),\n protectionMeasures: row.protectionMeasures,\n victimOpinion: row.victimOpinion,\n resultNotice: row.resultToldOn ? row.resultNotice : null,\n resultToldOn: row.resultToldOn,\n closedOn: row.closedOn\n } as ComplianceReportView\n}\n\n/** The cases the request reported, or that happened to them - each as a party reads it. */\nexport async function myComplianceReports(context: any): Promise<ComplianceReportView[]> {\n const { domain, user } = context.state\n const viewer = await caseViewerOf(context)\n const queryBuilder = getRepository(ComplianceCase).createQueryBuilder('cc').where('cc.domain = :domain', { domain: domain.id })\n if (viewer.employeeIds.length) queryBuilder.andWhere('(cc.reporterUser = :me OR cc.victim IN (:...mine))', { me: user.id, mine: viewer.employeeIds })\n else queryBuilder.andWhere('cc.reporterUser = :me', { me: user.id })\n const rows = await queryBuilder.orderBy('cc.receivedOn', 'DESC').getMany()\n const views: ComplianceReportView[] = []\n for (const one of rows) {\n const row = await getRepository(ComplianceCase).findOne({ where: { id: one.id } as any, relations: RELATIONS })\n const facts = await factsOf(row!)\n /* The party view, whatever more the reader may read on the handlers' side. */\n const party = caseSightOf(facts, { ...viewer, handler: false })\n if (party) views.push(await reportViewOf(row!, facts.reporterUserId === user.id ? 'REPORTER' : 'VICTIM', context))\n }\n await recordCaseRead(context, views.map(one => one.id), 'PARTY')\n return views\n}\n\n/** The employees still working here a reporter may name, found by name - for a working employee only. */\nexport async function casePeople(words: string, context: any): Promise<ComplianceCasePerson[]> {\n const { domain } = context.state\n await requireWorkingEmployee(context)\n const wanted = (words ?? '').trim().toLowerCase()\n if (!wanted) return []\n const today = todayIn(domain)\n const employees = await getRepository(Employee).find({ where: { domain: { id: domain.id } } as any, order: { name: 'ASC' } as any })\n return employees\n .filter(one => one.active !== false && (!one.retiredOn || one.retiredOn > today) && one.name?.toLowerCase().includes(wanted))\n .slice(0, 20)\n .map(one => ({ id: one.id, name: one.name, note: one.controlNo }))\n}\n\n/** The users of the domain a handler may name as investigators, found by name or mail. */\nexport async function investigatorChoices(words: string, context: any): Promise<ComplianceCasePerson[]> {\n const wanted = (words ?? '').trim().toLowerCase()\n if (!wanted) return []\n return (await getDomainAssignees(context.state.domain))\n .filter(one => `${one.name ?? ''} ${one.email ?? ''}`.toLowerCase().includes(wanted))\n .slice(0, 20)\n .map(one => ({ id: one.id, name: one.name || one.email, note: one.email }))\n}\n\n/*\n * ---------------------------------------------------------------- files\n */\n\n/**\n * Who opens a file of a case. The report's files: those who read all of it, and the reporter their own. The\n * investigation's files: those who read all of it. Every opening is a read of the case, recorded.\n */\nexport async function mayReadCaseFile(attachment: Attachment, context: any): Promise<boolean> {\n const entry = attachment.refType === CASE_ENTRY_REF_TYPE\n const caseId = entry ? (await getRepository(ComplianceCaseEntry).findOne({ where: { id: attachment.refBy } as any }))?.complianceCaseId : attachment.refBy\n const found = caseId ? await caseInSight(caseId, context) : null\n if (!found) return false\n const allowed = found.sight === 'FULL' || (!entry && found.row.reporterUserId === context.state.user.id && attachment.creatorId === context.state.user.id)\n if (allowed) await recordCaseRead(context, [found.row.id], found.sight!)\n return allowed\n}\n\n/*\n * ---------------------------------------------------------------- the management check (ADR-0146)\n */\n\n/**\n * Cases past their investigation-start day with no investigation started (decision 21). Only the day and the count -\n * a check is read by more than the case handlers, so nothing of a case is in it. A case left to the reporter alone,\n * with nobody inside to investigate it, is not on it.\n */\nexport async function complianceCasesNotInvestigated(tx: EntityManager, domain: Domain, today: string): Promise<{ id: string; receivedOn: string; investigationDueOn: string }[]> {\n const open = await tx.getRepository(ComplianceCase).find({ where: { domain: { id: domain.id }, noInsideHandler: false } as any, order: { receivedOn: 'ASC' } as any })\n return open.filter(one => investigationLate(one, today)).map(one => ({ id: one.id, receivedOn: one.receivedOn, investigationDueOn: one.investigationDueOn! }))\n}\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Attachment } from '@things-factory/attachment-base';
|
|
2
|
+
import { ComplianceCase, ComplianceCaseKind, ComplianceCaseStatus } from './compliance-case';
|
|
3
|
+
export declare class NewComplianceCaseReport {
|
|
4
|
+
kind: ComplianceCaseKind;
|
|
5
|
+
victimId?: string;
|
|
6
|
+
accusedIds: string[];
|
|
7
|
+
occurredOn?: string;
|
|
8
|
+
description: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class NewComplianceCase extends NewComplianceCaseReport {
|
|
11
|
+
reporterId?: string;
|
|
12
|
+
receivedOn: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class ComplianceCaseHandling {
|
|
15
|
+
id: string;
|
|
16
|
+
investigatorIds?: string[];
|
|
17
|
+
investigationStartedOn?: string;
|
|
18
|
+
protectionMeasures?: string;
|
|
19
|
+
victimOpinion?: string;
|
|
20
|
+
finding?: string;
|
|
21
|
+
actionOnAccused?: string;
|
|
22
|
+
resultNotice?: string;
|
|
23
|
+
resultToldOn?: string;
|
|
24
|
+
closedOn?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare class ComplianceCaseList {
|
|
27
|
+
items: ComplianceCase[];
|
|
28
|
+
total: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A case as the reporter or the victim reads it - where it stands, the protection measures and the result told; the
|
|
32
|
+
* reporter also what they reported. No investigation is on this type, so no door answering it can hand one out.
|
|
33
|
+
*/
|
|
34
|
+
export declare class ComplianceReportView {
|
|
35
|
+
id: string;
|
|
36
|
+
kind: ComplianceCaseKind;
|
|
37
|
+
status: ComplianceCaseStatus;
|
|
38
|
+
standing: string;
|
|
39
|
+
receivedOn: string;
|
|
40
|
+
noInsideHandler: boolean;
|
|
41
|
+
occurredOn?: string;
|
|
42
|
+
description?: string;
|
|
43
|
+
accusedNames?: string[];
|
|
44
|
+
victimName?: string;
|
|
45
|
+
protectionMeasures?: string;
|
|
46
|
+
victimOpinion?: string;
|
|
47
|
+
resultNotice?: string;
|
|
48
|
+
resultToldOn?: string;
|
|
49
|
+
closedOn?: string;
|
|
50
|
+
attachments?: Attachment[];
|
|
51
|
+
}
|
|
52
|
+
export declare class ComplianceCasePerson {
|
|
53
|
+
id: string;
|
|
54
|
+
name: string;
|
|
55
|
+
note?: string;
|
|
56
|
+
}
|