@things-factory/organization 10.1.233 → 10.1.236

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 (42) hide show
  1. package/dist-client/component/approval-line-edit.d.ts +9 -0
  2. package/dist-client/component/approval-line-edit.js +8 -0
  3. package/dist-client/component/approval-line-edit.js.map +1 -1
  4. package/dist-client/component/approval-line-items-editor.js +2 -2
  5. package/dist-client/component/approval-line-items-editor.js.map +1 -1
  6. package/dist-client/component/approval-line-templates-manager.js +2 -1
  7. package/dist-client/component/approval-line-templates-manager.js.map +1 -1
  8. package/dist-client/component/assignees-editor.js +2 -1
  9. package/dist-client/component/assignees-editor.js.map +1 -1
  10. package/dist-client/component/recipients-editor.js +2 -1
  11. package/dist-client/component/recipients-editor.js.map +1 -1
  12. package/dist-client/tsconfig.tsbuildinfo +1 -1
  13. package/dist-server/ai-entry/organization-entry-rules.js +3 -3
  14. package/dist-server/ai-entry/organization-entry-rules.js.map +1 -1
  15. package/dist-server/service/approval-line/approval-line-mutation.js +7 -5
  16. package/dist-server/service/approval-line/approval-line-mutation.js.map +1 -1
  17. package/dist-server/service/department/department-mutation.js +2 -1
  18. package/dist-server/service/department/department-mutation.js.map +1 -1
  19. package/dist-server/service/department/department-parent.js +3 -2
  20. package/dist-server/service/department/department-parent.js.map +1 -1
  21. package/dist-server/service/domain-reference.d.ts +1 -1
  22. package/dist-server/service/domain-reference.js +2 -2
  23. package/dist-server/service/domain-reference.js.map +1 -1
  24. package/dist-server/service/employee/employee-control-no.d.ts +12 -0
  25. package/dist-server/service/employee/employee-control-no.js +27 -0
  26. package/dist-server/service/employee/employee-control-no.js.map +1 -0
  27. package/dist-server/service/employee/employee-day.js +4 -1
  28. package/dist-server/service/employee/employee-day.js.map +1 -1
  29. package/dist-server/service/employee/employee-mutation.js +12 -3
  30. package/dist-server/service/employee/employee-mutation.js.map +1 -1
  31. package/dist-server/service/employee-profile/employee-profile-query.js +3 -2
  32. package/dist-server/service/employee-profile/employee-profile-query.js.map +1 -1
  33. package/dist-server/tsconfig.tsbuildinfo +1 -1
  34. package/package.json +7 -7
  35. package/tests/assignees-editor-no-role.test.ts +2 -2
  36. package/tests/refusals-in-korean.test.ts +48 -0
  37. package/translations/en.json +13 -1
  38. package/translations/es.json +13 -1
  39. package/translations/ja.json +13 -1
  40. package/translations/ko.json +13 -1
  41. package/translations/ms.json +13 -1
  42. package/translations/zh.json +13 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/organization",
3
- "version": "10.1.233",
3
+ "version": "10.1.236",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -37,12 +37,12 @@
37
37
  "@operato/p13n": "^10.0.0",
38
38
  "@operato/popup": "^10.15.0",
39
39
  "@operato/shell": "^10.0.0",
40
- "@things-factory/auth-base": "^10.1.232",
41
- "@things-factory/code-ui": "^10.1.232",
42
- "@things-factory/contact": "^10.1.233",
43
- "@things-factory/pdf": "^10.1.233",
44
- "@things-factory/shell": "^10.1.228",
40
+ "@things-factory/auth-base": "^10.1.234",
41
+ "@things-factory/code-ui": "^10.1.234",
42
+ "@things-factory/contact": "^10.1.236",
43
+ "@things-factory/pdf": "^10.1.234",
44
+ "@things-factory/shell": "^10.1.234",
45
45
  "exceljs": "4.2.0"
46
46
  },
47
- "gitHead": "8ce73f35075a23dafe2785eb31735b459659a757"
47
+ "gitHead": "1560112ae8ae5a5d296b4fce1d5a1be05e30e8c2"
48
48
  }
@@ -14,7 +14,7 @@ describe('the assignees editor', () => {
14
14
  const source = read('client/component/assignees-editor.ts')
15
15
 
16
16
  it('does not offer Role as an assignee type', () => {
17
- const options = source.match(/options: \[(''[^\]]*)\]/)?.[1] ?? ''
17
+ const options = source.match(/options: targetTypeOptions\(\[([^\]]*)\]/)?.[1] ?? ''
18
18
  expect(options).toMatch(/'Employee'/)
19
19
  expect(options).not.toMatch(/'Role'/)
20
20
  })
@@ -27,6 +27,6 @@ describe('the assignees editor', () => {
27
27
 
28
28
  describe('the approval-line editor', () => {
29
29
  it('keeps Role', () => {
30
- expect(read('client/component/approval-line-items-editor.ts')).toMatch(/options: \['', 'Employee', 'Department', 'Role'/)
30
+ expect(read('client/component/approval-line-items-editor.ts')).toMatch(/options: targetTypeOptions\(\['Employee', 'Department', 'Role'/)
31
31
  })
32
32
  })
@@ -0,0 +1,48 @@
1
+ /*
2
+ * Inline help audit 2026-10-30: the roster and department doors threw English sentences - 「hiredOn must be a calendar
3
+ * day in YYYY-MM-DD format」, 「manager not found in this domain: <uuid>」, 「There is no employee <uuid>.」, 「a department
4
+ * cannot be placed under itself…」 - and the department resolver did not speak refusals. Each is a refusal with its
5
+ * Korean sentence now, naming the field instead of the property.
6
+ */
7
+ import { readFileSync, readdirSync } from 'fs'
8
+ import { join } from 'path'
9
+
10
+ import { toDay } from '../server/service/employee/employee-day'
11
+
12
+ const ROOT = join(__dirname, '..')
13
+ const read = (file: string) => readFileSync(join(ROOT, file), 'utf8')
14
+ const ko: Record<string, string> = JSON.parse(read('translations/ko.json'))
15
+
16
+ const sources = (dir: string): string[] =>
17
+ readdirSync(dir, { withFileTypes: true }).flatMap(entry => (entry.isDirectory() ? sources(join(dir, entry.name)) : /\.ts$/.test(entry.name) && !/\.test\.ts$/.test(entry.name) ? [join(dir, entry.name)] : []))
18
+ const text = sources(join(ROOT, 'server')).map(file => readFileSync(file, 'utf8')).join('\n')
19
+
20
+ test('★ every refusal the server throws has its Korean sentence', () => {
21
+ const codes = new Set([...text.matchAll(/new Refusal\(\s*'([a-z0-9-]+)'/g)].map(match => match[1]))
22
+ for (const what of ['manager', 'supervisor', 'department']) codes.add(`${what}-not-in-domain`)
23
+ for (const code of ['hired-on-invalid', 'retired-on-invalid']) codes.add(code)
24
+ expect(codes.size).toBeGreaterThanOrEqual(15)
25
+ expect([...codes].filter(code => !(`error.${code}` in ko))).toEqual([])
26
+ })
27
+
28
+ test('★ the reference, day, parent and employee doors throw no English sentence', () => {
29
+ for (const file of [
30
+ 'server/service/domain-reference.ts',
31
+ 'server/service/employee/employee-day.ts',
32
+ 'server/service/department/department-parent.ts',
33
+ 'server/service/employee/employee-mutation.ts',
34
+ 'server/service/employee-profile/employee-profile-query.ts'
35
+ ]) {
36
+ expect({ file, english: read(file).match(/throw new Error\(\s*['`][A-Za-z][^'`]*['`]/g) ?? [] }).toEqual({ file, english: [] })
37
+ }
38
+ })
39
+
40
+ test('★ a day that is not a day is refused by its field, in words', () => {
41
+ expect(() => toDay('hiredOn', '2026-02-30')).toThrow(expect.objectContaining({ code: 'hired-on-invalid', params: { value: '2026-02-30' } }))
42
+ expect(ko['error.hired-on-invalid']).toContain('입사일')
43
+ })
44
+
45
+ test('★ the department and employee-profile resolvers speak their refusals', () => {
46
+ expect(read('server/service/department/department-mutation.ts')).toMatch(/@Resolver\(Department\)\n@UseMiddleware\(SpeakRefusals\)/)
47
+ expect(read('server/service/employee-profile/employee-profile-query.ts')).toMatch(/@Resolver\(EmployeeProfile\)\n@UseMiddleware\(SpeakRefusals\)/)
48
+ })
@@ -194,5 +194,17 @@
194
194
  "error.employee-not-found": "The employee was not found.",
195
195
  "button.issue-employment-certificate": "Issue employment certificate",
196
196
  "button.issue-career-certificate": "Issue career certificate",
197
- "text.select-one-employee": "Select one employee"
197
+ "text.select-one-employee": "Select one employee",
198
+ "error.employee-control-no-required": "Enter the employee number.",
199
+ "error.employee-control-no-taken": "Employee number {value} is already another employee's.",
200
+ "error.approval-line-approver-required": "Choose the approver on row {row}.",
201
+ "error.manager-not-in-domain": "The manager chosen is not in this domain. Choose again.",
202
+ "error.supervisor-not-in-domain": "The supervisor chosen is not in this domain. Choose again.",
203
+ "error.department-not-in-domain": "The department chosen is not in this domain. Choose again.",
204
+ "error.user-not-in-domain": "The user chosen is not a user of this domain. Choose one of this domain.",
205
+ "error.hired-on-invalid": "The hire date is a day written as 2026-01-31. Received: {value}",
206
+ "error.retired-on-invalid": "The leaving date is a day written as 2026-01-31. Received: {value}",
207
+ "error.department-parent-not-found": "The parent department chosen is not in this domain. Choose again.",
208
+ "error.department-parent-loop": "A department cannot be placed under itself or under one of its own sub-departments.",
209
+ "error.document-language-not-run": "The application does not run the language {language}."
198
210
  }
@@ -194,5 +194,17 @@
194
194
  "error.employee-not-found": "No se encontró el empleado.",
195
195
  "button.issue-employment-certificate": "Emitir certificado de empleo",
196
196
  "button.issue-career-certificate": "Emitir certificado de experiencia",
197
- "text.select-one-employee": "Seleccione un empleado"
197
+ "text.select-one-employee": "Seleccione un empleado",
198
+ "error.employee-control-no-required": "Introduzca el número de empleado.",
199
+ "error.employee-control-no-taken": "El número de empleado {value} ya lo usa otro empleado.",
200
+ "error.approval-line-approver-required": "Elija el aprobador de la fila {row}.",
201
+ "error.manager-not-in-domain": "El responsable elegido no está en este dominio. Elija de nuevo.",
202
+ "error.supervisor-not-in-domain": "El supervisor elegido no está en este dominio. Elija de nuevo.",
203
+ "error.department-not-in-domain": "El departamento elegido no está en este dominio. Elija de nuevo.",
204
+ "error.user-not-in-domain": "El usuario elegido no es de este dominio. Elija uno de este dominio.",
205
+ "error.hired-on-invalid": "La fecha de alta se escribe como 2026-01-31. Recibido: {value}",
206
+ "error.retired-on-invalid": "La fecha de baja se escribe como 2026-01-31. Recibido: {value}",
207
+ "error.department-parent-not-found": "El departamento superior elegido no está en este dominio. Elija de nuevo.",
208
+ "error.department-parent-loop": "Un departamento no puede ir bajo sí mismo ni bajo uno de sus subdepartamentos.",
209
+ "error.document-language-not-run": "La aplicación no usa el idioma {language}."
198
210
  }
@@ -194,5 +194,17 @@
194
194
  "error.employee-not-found": "社員が見つかりません。",
195
195
  "button.issue-employment-certificate": "在職証明書を発行",
196
196
  "button.issue-career-certificate": "経歴証明書を発行",
197
- "text.select-one-employee": "社員を一人選んでください"
197
+ "text.select-one-employee": "社員を一人選んでください",
198
+ "error.employee-control-no-required": "管理番号を入力してください。",
199
+ "error.employee-control-no-taken": "管理番号 {value} は既に別の社員が使っています。",
200
+ "error.approval-line-approver-required": "{row}行目の承認者を選んでください。",
201
+ "error.manager-not-in-domain": "管理者に選んだ社員がこの事業所にいません。選び直してください。",
202
+ "error.supervisor-not-in-domain": "上司に選んだ社員がこの事業所にいません。選び直してください。",
203
+ "error.department-not-in-domain": "選んだ部署がこの事業所にありません。選び直してください。",
204
+ "error.user-not-in-domain": "紐付けるユーザーはこの事業所のユーザーではありません。この事業所のユーザーを選んでください。",
205
+ "error.hired-on-invalid": "入社日は 2026-01-31 のように日付で入力してください。受け取った値: {value}",
206
+ "error.retired-on-invalid": "退社日は 2026-01-31 のように日付で入力してください。受け取った値: {value}",
207
+ "error.department-parent-not-found": "上位部署に選んだ部署がこの事業所にありません。選び直してください。",
208
+ "error.department-parent-loop": "部署を自分自身や自分の下位部署の下に移すことはできません。",
209
+ "error.document-language-not-run": "このアプリケーションが使わない言語です: {language}"
198
210
  }
@@ -194,5 +194,17 @@
194
194
  "error.employee-not-found": "직원을 찾을 수 없습니다.",
195
195
  "button.issue-employment-certificate": "재직증명서 발급",
196
196
  "button.issue-career-certificate": "경력증명서 발급",
197
- "text.select-one-employee": "직원 한 명을 고르세요"
197
+ "text.select-one-employee": "직원 한 명을 고르세요",
198
+ "error.employee-control-no-required": "관리 번호를 입력하세요.",
199
+ "error.employee-control-no-taken": "관리 번호 {value}은(는) 이미 다른 직원이 쓰고 있습니다.",
200
+ "error.approval-line-approver-required": "{row}번째 줄에 결재자를 고르세요.",
201
+ "error.manager-not-in-domain": "관리자로 고른 직원이 이 사업장에 없습니다. 다시 골라 주세요.",
202
+ "error.supervisor-not-in-domain": "상사로 고른 직원이 이 사업장에 없습니다. 다시 골라 주세요.",
203
+ "error.department-not-in-domain": "고른 부서가 이 사업장에 없습니다. 다시 골라 주세요.",
204
+ "error.user-not-in-domain": "연결할 사용자가 이 사업장의 사용자가 아닙니다. 이 사업장의 사용자를 골라 주세요.",
205
+ "error.hired-on-invalid": "입사일은 2026-01-31 처럼 날짜로 적어 주세요. 받은 값: {value}",
206
+ "error.retired-on-invalid": "퇴사일은 2026-01-31 처럼 날짜로 적어 주세요. 받은 값: {value}",
207
+ "error.department-parent-not-found": "상위 부서로 고른 부서가 이 사업장에 없습니다. 다시 골라 주세요.",
208
+ "error.department-parent-loop": "부서를 자기 자신이나 자기 하위 부서 아래로 옮길 수 없습니다.",
209
+ "error.document-language-not-run": "이 애플리케이션이 쓰지 않는 언어입니다: {language}"
198
210
  }
@@ -194,5 +194,17 @@
194
194
  "error.employee-not-found": "Pekerja tidak ditemui.",
195
195
  "button.issue-employment-certificate": "Keluarkan sijil pekerjaan",
196
196
  "button.issue-career-certificate": "Keluarkan sijil pengalaman",
197
- "text.select-one-employee": "Pilih seorang pekerja"
197
+ "text.select-one-employee": "Pilih seorang pekerja",
198
+ "error.employee-control-no-required": "Masukkan nombor pekerja.",
199
+ "error.employee-control-no-taken": "Nombor pekerja {value} sudah digunakan oleh pekerja lain.",
200
+ "error.approval-line-approver-required": "Pilih pelulus pada baris {row}.",
201
+ "error.manager-not-in-domain": "Pengurus yang dipilih tiada dalam domain ini. Pilih semula.",
202
+ "error.supervisor-not-in-domain": "Penyelia yang dipilih tiada dalam domain ini. Pilih semula.",
203
+ "error.department-not-in-domain": "Jabatan yang dipilih tiada dalam domain ini. Pilih semula.",
204
+ "error.user-not-in-domain": "Pengguna yang dipilih bukan pengguna domain ini. Pilih pengguna domain ini.",
205
+ "error.hired-on-invalid": "Tarikh mula kerja ditulis seperti 2026-01-31. Diterima: {value}",
206
+ "error.retired-on-invalid": "Tarikh berhenti ditulis seperti 2026-01-31. Diterima: {value}",
207
+ "error.department-parent-not-found": "Jabatan induk yang dipilih tiada dalam domain ini. Pilih semula.",
208
+ "error.department-parent-loop": "Jabatan tidak boleh diletakkan di bawah dirinya atau sub-jabatannya sendiri.",
209
+ "error.document-language-not-run": "Aplikasi ini tidak menggunakan bahasa {language}."
198
210
  }
@@ -194,5 +194,17 @@
194
194
  "error.employee-not-found": "找不到员工。",
195
195
  "button.issue-employment-certificate": "签发在职证明",
196
196
  "button.issue-career-certificate": "签发经历证明",
197
- "text.select-one-employee": "请选择一名员工"
197
+ "text.select-one-employee": "请选择一名员工",
198
+ "error.employee-control-no-required": "请输入员工编号。",
199
+ "error.employee-control-no-taken": "员工编号 {value} 已被其他员工使用。",
200
+ "error.approval-line-approver-required": "请为第 {row} 行选择审批人。",
201
+ "error.manager-not-in-domain": "所选管理者不在此域中。请重新选择。",
202
+ "error.supervisor-not-in-domain": "所选上级不在此域中。请重新选择。",
203
+ "error.department-not-in-domain": "所选部门不在此域中。请重新选择。",
204
+ "error.user-not-in-domain": "所选用户不是此域的用户。请选择此域的用户。",
205
+ "error.hired-on-invalid": "入职日期请按 2026-01-31 的格式填写。收到的值: {value}",
206
+ "error.retired-on-invalid": "离职日期请按 2026-01-31 的格式填写。收到的值: {value}",
207
+ "error.department-parent-not-found": "所选上级部门不在此域中。请重新选择。",
208
+ "error.department-parent-loop": "部门不能放在自身或其下级部门之下。",
209
+ "error.document-language-not-run": "此应用不支持该语言: {language}"
198
210
  }