@things-factory/organization 7.0.71 → 7.0.72

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 (28) hide show
  1. package/client/component/department-selector.ts +7 -2
  2. package/client/pages/employee/employee-list-page.ts +39 -5
  3. package/dist-client/component/department-selector.d.ts +1 -1
  4. package/dist-client/component/department-selector.js +6 -2
  5. package/dist-client/component/department-selector.js.map +1 -1
  6. package/dist-client/pages/employee/employee-list-page.d.ts +1 -0
  7. package/dist-client/pages/employee/employee-list-page.js +36 -5
  8. package/dist-client/pages/employee/employee-list-page.js.map +1 -1
  9. package/dist-client/tsconfig.tsbuildinfo +1 -1
  10. package/dist-server/controllers/register-employee-as-system-user.d.ts +5 -1
  11. package/dist-server/controllers/register-employee-as-system-user.js +87 -35
  12. package/dist-server/controllers/register-employee-as-system-user.js.map +1 -1
  13. package/dist-server/service/employee/employee-mutation.d.ts +1 -1
  14. package/dist-server/service/employee/employee-mutation.js +68 -60
  15. package/dist-server/service/employee/employee-mutation.js.map +1 -1
  16. package/dist-server/service/employee/employee-query.d.ts +2 -2
  17. package/dist-server/service/employee/employee-query.js +18 -10
  18. package/dist-server/service/employee/employee-query.js.map +1 -1
  19. package/dist-server/tsconfig.tsbuildinfo +1 -1
  20. package/package.json +6 -6
  21. package/server/controllers/register-employee-as-system-user.ts +111 -37
  22. package/server/service/employee/employee-mutation.ts +83 -63
  23. package/server/service/employee/employee-query.ts +23 -12
  24. package/translations/en.json +5 -1
  25. package/translations/ja.json +5 -1
  26. package/translations/ko.json +5 -1
  27. package/translations/ms.json +4 -1
  28. package/translations/zh.json +5 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/organization",
3
- "version": "7.0.71",
3
+ "version": "7.0.72",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -33,10 +33,10 @@
33
33
  "@operato/graphql": "^7.0.0",
34
34
  "@operato/p13n": "^7.0.0",
35
35
  "@operato/shell": "^7.0.0",
36
- "@things-factory/auth-base": "^7.0.71",
37
- "@things-factory/code-ui": "^7.0.71",
38
- "@things-factory/contact": "^7.0.71",
39
- "@things-factory/shell": "^7.0.70"
36
+ "@things-factory/auth-base": "^7.0.72",
37
+ "@things-factory/code-ui": "^7.0.72",
38
+ "@things-factory/contact": "^7.0.72",
39
+ "@things-factory/shell": "^7.0.72"
40
40
  },
41
- "gitHead": "d242e4a4415764d0d389e9dff09d2ce3a8fc317f"
41
+ "gitHead": "6131a0f20fcc11bc8e9e9d839de8e9700a2b0ac0"
42
42
  }
@@ -1,62 +1,136 @@
1
- import { Role, User } from '@things-factory/auth-base'
2
- import { Contact } from '@things-factory/contact'
3
1
  import { getRepository } from '@things-factory/shell'
4
- import { Employee } from 'service'
2
+ import { Employee } from '../service/employee/employee'
3
+ import { registerContactAsSystemUser } from '@things-factory/contact'
4
+ import { Role, User } from '@things-factory/auth-base'
5
+ import { EmployeePatch } from 'service/employee/employee-type'
5
6
 
6
7
  export async function registerEmployeeAsSystemUser(employeeId: string, context: ResolverContext) {
7
- /*
8
- process
9
-
10
- 0. 이미 연결된 사용자가 없어야 한다.
11
- 1. contact 정보가 있어야 한다.
12
- 2. contact 정보에 대표 email 정보가 있어야 한다.
13
- 3. employee 의 직책 정보가 있어야 한다. => role 과 연결된다.
14
- 4. 사용자 중에서 동일한 이메일을 가진 사용자가 있는가 확인한다.
15
- 5. 그 사용자가 이 도메인에 연결되어 있는 지 확인한다. 없다면 실패.
16
- 6. 직책에 해당하는 역할이 있는 지 확인한다.
17
- 7. 시스템에 사용자를 등록한다.
18
- 8. 역할을 추가한다.
19
- */
8
+ const { domain, tx } = context.state
20
9
 
21
- const { domain, user } = context.state
22
-
23
- const employeeRepository = getRepository(Employee)
10
+ const employeeRepository = getRepository(Employee, tx)
24
11
 
25
12
  const employee = await employeeRepository.findOne({
26
13
  where: {
27
14
  id: employeeId,
28
15
  domain: { id: domain.id }
29
16
  },
30
- relations: ['contact']
17
+ relations: ['contact', 'user']
31
18
  })
32
19
 
33
- const { email } = employee.contact
34
- const { jobResponsibility } = employee
20
+ if (employee.user) {
21
+ throw new Error(context.t('error.employee-already-registered'))
22
+ }
23
+
24
+ if (!employee.contact) {
25
+ throw new Error(context.t('error.contact-information-required'))
26
+ }
35
27
 
36
- const userRepository = getRepository(User)
37
- const existingUser = await userRepository.findOne({
28
+ const systemUser = await registerContactAsSystemUser(
29
+ {
30
+ contactId: employee.contact.id,
31
+ roleName: employee.active ? employee.jobResponsibility : ''
32
+ },
33
+ context
34
+ )
35
+
36
+ employee.user = systemUser
37
+
38
+ await employeeRepository.save(employee)
39
+
40
+ return systemUser
41
+ }
42
+
43
+ export async function onUpdateEmployeeAsSystemUser(patch: EmployeePatch, context: ResolverContext) {
44
+ const { domain, user, tx } = context.state
45
+ const { id, jobResponsibility } = patch
46
+
47
+ const employeeRepository = getRepository(Employee, tx)
48
+
49
+ const employee = await employeeRepository.findOne({
38
50
  where: {
39
- email
51
+ id,
52
+ domain: { id: domain.id }
40
53
  },
41
- relations: ['domains']
54
+ relations: ['contact', 'user']
42
55
  })
43
56
 
44
- const newUser = await userRepository.save({
45
- name: employee.contact.name,
46
- email
47
- })
57
+ if (!employee.user) {
58
+ return
59
+ }
60
+
61
+ const { jobResponsibility: lastJobResponsibility } = employee
62
+
63
+ if ('jobResponsibility' in patch && lastJobResponsibility !== jobResponsibility) {
64
+ const userRepository = getRepository(User, tx)
65
+
66
+ const systemUser = await userRepository.findOne({
67
+ where: { id: employee.user.id },
68
+ relations: ['domains', 'roles']
69
+ })
70
+
71
+ const { roles } = systemUser
72
+ let newRoles = [...roles]
48
73
 
49
- // permission for this domain
74
+ if (lastJobResponsibility) {
75
+ const lastRole = await getRepository(Role, tx).findOne({
76
+ where: { name: lastJobResponsibility, domain: { id: domain.id } }
77
+ })
50
78
 
51
- const roleRepository = getRepository(Role)
52
- const existingRole = await roleRepository.findOne({
79
+ if (lastRole) {
80
+ newRoles = roles.filter(role => role.id !== lastRole.id)
81
+ }
82
+ }
83
+
84
+ const newRole = await getRepository(Role, tx).findOne({
85
+ where: { name: jobResponsibility, domain: { id: domain.id } }
86
+ })
87
+
88
+ if (newRole && !roles.find(role => role.id === newRole.id)) {
89
+ newRoles = [...newRoles, newRole]
90
+ }
91
+
92
+ systemUser.roles = newRoles
93
+ systemUser.updater = user
94
+
95
+ await userRepository.save(systemUser)
96
+ }
97
+ }
98
+
99
+ export async function onDeleteEmployeeAsSystemUser(employeeId: string, context: ResolverContext) {
100
+ const { domain, user, tx } = context.state
101
+
102
+ const employeeRepository = getRepository(Employee, tx)
103
+
104
+ const employee = await employeeRepository.findOne({
53
105
  where: {
54
- name: jobResponsibility,
106
+ id: employeeId,
55
107
  domain: { id: domain.id }
56
- }
108
+ },
109
+ relations: ['user']
57
110
  })
58
111
 
59
- // permission for this role
112
+ if (!employee.user) {
113
+ return
114
+ }
115
+
116
+ const { jobResponsibility } = employee
117
+
118
+ if (jobResponsibility) {
119
+ const userRepository = getRepository(User, tx)
120
+
121
+ const systemUser = await userRepository.findOne({
122
+ where: { id: employee.user.id },
123
+ relations: ['domains', 'roles']
124
+ })
60
125
 
61
- return true
126
+ const lastRole = await getRepository(Role, tx).findOne({
127
+ where: { name: jobResponsibility, domain: { id: domain.id } }
128
+ })
129
+
130
+ if (lastRole) {
131
+ systemUser.roles = systemUser.roles.filter(role => role.id !== lastRole.id)
132
+ systemUser.updater = user
133
+ await userRepository.save(systemUser)
134
+ }
135
+ }
62
136
  }
@@ -1,6 +1,7 @@
1
1
  import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
2
  import { In } from 'typeorm'
3
3
 
4
+ import { getRepository } from '@things-factory/shell'
4
5
  import { User } from '@things-factory/auth-base'
5
6
  import { createAttachment, deleteAttachmentsByRef } from '@things-factory/attachment-base'
6
7
  import { Contact } from '@things-factory/contact'
@@ -9,29 +10,39 @@ import { Employee } from './employee'
9
10
  import { NewEmployee, EmployeePatch } from './employee-type'
10
11
  import { Department } from '../department/department'
11
12
 
13
+ import {
14
+ onDeleteEmployeeAsSystemUser,
15
+ onUpdateEmployeeAsSystemUser,
16
+ registerEmployeeAsSystemUser
17
+ } from '../../controllers/register-employee-as-system-user'
18
+
12
19
  @Resolver(Employee)
13
20
  export class EmployeeMutation {
14
21
  @Directive('@transaction')
15
- @Mutation(returns => Employee, { description: 'To create new Employee' })
22
+ @Directive('@privilege(category: "employee", privilege: "mutation", domainOwnerGranted: true)')
23
+ @Mutation(returns => Employee, {
24
+ description:
25
+ 'Creates a new employee record with the provided details. Optionally associates the employee with a supervisor, department, and system user. If a photo is provided, it will be attached to the employee record.'
26
+ })
16
27
  async createEmployee(@Arg('employee') employee: NewEmployee, @Ctx() context: ResolverContext): Promise<Employee> {
17
28
  const { domain, user, tx } = context.state
18
29
 
19
30
  const supervisor =
20
31
  'supervisor' in employee
21
- ? employee.supervisor && (await tx.getRepository(Employee).findOneBy({ id: employee.supervisor.id }))
32
+ ? employee.supervisor && (await getRepository(Employee, tx).findOneBy({ id: employee.supervisor.id }))
22
33
  : undefined
23
34
 
24
35
  const department =
25
36
  'department' in employee
26
- ? employee.department && (await tx.getRepository(Department).findOneBy({ id: employee.department.id }))
37
+ ? employee.department && (await getRepository(Department, tx).findOneBy({ id: employee.department.id }))
27
38
  : undefined
28
39
 
29
40
  const connectedUser =
30
41
  'user' in employee
31
- ? employee.user && (await tx.getRepository(User).findOneBy({ id: employee.user.id }))
42
+ ? employee.user && (await getRepository(User, tx).findOneBy({ id: employee.user.id }))
32
43
  : undefined
33
44
 
34
- const result = await tx.getRepository(Employee).save({
45
+ const result = await getRepository(Employee, tx).save({
35
46
  ...employee,
36
47
  supervisor,
37
48
  department,
@@ -59,7 +70,11 @@ export class EmployeeMutation {
59
70
  }
60
71
 
61
72
  @Directive('@transaction')
62
- @Mutation(returns => Employee, { description: 'To modify Employee information' })
73
+ @Directive('@privilege(category: "employee", privilege: "mutation", domainOwnerGranted: true)')
74
+ @Mutation(returns => Employee, {
75
+ description:
76
+ 'Updates the details of an existing employee identified by the given ID. Optionally updates the supervisor, department, system user, and photo associated with the employee.'
77
+ })
63
78
  async updateEmployee(
64
79
  @Arg('id') id: string,
65
80
  @Arg('patch') patch: EmployeePatch,
@@ -69,22 +84,24 @@ export class EmployeeMutation {
69
84
 
70
85
  const supervisor =
71
86
  'supervisor' in patch
72
- ? patch.supervisor && (await tx.getRepository(Employee).findOneBy({ id: patch.supervisor.id }))
87
+ ? patch.supervisor && (await getRepository(Employee, tx).findOneBy({ id: patch.supervisor.id }))
73
88
  : undefined
74
89
 
75
90
  const department =
76
91
  'department' in patch
77
- ? patch.department && (await tx.getRepository(Department).findOneBy({ id: patch.department.id }))
92
+ ? patch.department && (await getRepository(Department, tx).findOneBy({ id: patch.department.id }))
78
93
  : undefined
79
94
 
80
95
  const connectedUser =
81
- 'user' in patch ? patch.user && (await tx.getRepository(User).findOneBy({ id: patch.user.id })) : undefined
96
+ 'user' in patch ? patch.user && (await getRepository(User, tx).findOneBy({ id: patch.user.id })) : undefined
82
97
 
83
- const repository = tx.getRepository(Employee)
98
+ const repository = getRepository(Employee, tx)
84
99
  const employee = await repository.findOne({
85
100
  where: { domain: { id: domain.id }, id }
86
101
  })
87
102
 
103
+ onUpdateEmployeeAsSystemUser(patch, context)
104
+
88
105
  const result = await repository.save({
89
106
  ...employee,
90
107
  ...patch,
@@ -113,7 +130,11 @@ export class EmployeeMutation {
113
130
  }
114
131
 
115
132
  @Directive('@transaction')
116
- @Mutation(returns => [Employee], { description: "To modify multiple Employees' information" })
133
+ @Directive('@privilege(category: "employee", privilege: "mutation", domainOwnerGranted: true)')
134
+ @Mutation(returns => [Employee], {
135
+ description:
136
+ 'Updates or creates multiple employee records based on the provided patches. New employees are created if the "cuFlag" is "+", and existing employees are updated if the "cuFlag" is "M".'
137
+ })
117
138
  async updateMultipleEmployee(
118
139
  @Arg('patches', type => [EmployeePatch]) patches: EmployeePatch[],
119
140
  @Ctx() context: ResolverContext
@@ -123,7 +144,7 @@ export class EmployeeMutation {
123
144
  let results = []
124
145
  const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
125
146
  const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
126
- const employeeRepo = tx.getRepository(Employee)
147
+ const employeeRepo = getRepository(Employee, tx)
127
148
 
128
149
  if (_createRecords.length > 0) {
129
150
  for (let i = 0; i < _createRecords.length; i++) {
@@ -131,17 +152,17 @@ export class EmployeeMutation {
131
152
 
132
153
  const supervisor =
133
154
  'supervisor' in newRecord
134
- ? newRecord.supervisor && (await tx.getRepository(Employee).findOneBy({ id: newRecord.supervisor.id }))
155
+ ? newRecord.supervisor && (await getRepository(Employee, tx).findOneBy({ id: newRecord.supervisor.id }))
135
156
  : undefined
136
157
 
137
158
  const department =
138
159
  'department' in newRecord
139
- ? newRecord.department && (await tx.getRepository(Department).findOneBy({ id: newRecord.department.id }))
160
+ ? newRecord.department && (await getRepository(Department, tx).findOneBy({ id: newRecord.department.id }))
140
161
  : undefined
141
162
 
142
163
  const connectedUser =
143
164
  'user' in newRecord
144
- ? newRecord.user && (await tx.getRepository(User).findOneBy({ id: newRecord.user.id }))
165
+ ? newRecord.user && (await getRepository(User, tx).findOneBy({ id: newRecord.user.id }))
145
166
  : undefined
146
167
 
147
168
  const result = await employeeRepo.save({
@@ -179,22 +200,24 @@ export class EmployeeMutation {
179
200
  const supervisor =
180
201
  'supervisor' in updateRecord
181
202
  ? updateRecord.supervisor &&
182
- (await tx.getRepository(Employee).findOneBy({ id: updateRecord.supervisor.id }))
203
+ (await getRepository(Employee, tx).findOneBy({ id: updateRecord.supervisor.id }))
183
204
  : undefined
184
205
 
185
206
  const department =
186
207
  'department' in updateRecord
187
208
  ? updateRecord.department &&
188
- (await tx.getRepository(Department).findOneBy({ id: updateRecord.department.id }))
209
+ (await getRepository(Department, tx).findOneBy({ id: updateRecord.department.id }))
189
210
  : undefined
190
211
 
191
212
  const connectedUser =
192
213
  'user' in updateRecord
193
- ? updateRecord.user && (await tx.getRepository(User).findOneBy({ id: updateRecord.user.id }))
214
+ ? updateRecord.user && (await getRepository(User, tx).findOneBy({ id: updateRecord.user.id }))
194
215
  : undefined
195
216
 
196
217
  const employee = await employeeRepo.findOneBy({ id: updateRecord.id })
197
218
 
219
+ onUpdateEmployeeAsSystemUser(updateRecord, context)
220
+
198
221
  const result = await employeeRepo.save({
199
222
  ...employee,
200
223
  ...updateRecord,
@@ -227,25 +250,38 @@ export class EmployeeMutation {
227
250
  }
228
251
 
229
252
  @Directive('@transaction')
230
- @Mutation(returns => Boolean, { description: 'To delete Employee' })
253
+ @Directive('@privilege(category: "employee", privilege: "mutation", domainOwnerGranted: true)')
254
+ @Mutation(returns => Boolean, {
255
+ description:
256
+ 'Deletes an employee record identified by the given ID. Also deletes any attachments associated with the employee.'
257
+ })
231
258
  async deleteEmployee(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
232
259
  const { domain, tx } = context.state
233
260
 
234
- await tx.getRepository(Employee).delete({ domain: { id: domain.id }, id })
261
+ onDeleteEmployeeAsSystemUser(id, context)
262
+ await getRepository(Employee, tx).delete({ domain: { id: domain.id }, id })
235
263
  await deleteAttachmentsByRef(null, { refBys: [id] }, context)
236
264
 
237
265
  return true
238
266
  }
239
267
 
240
268
  @Directive('@transaction')
241
- @Mutation(returns => Boolean, { description: 'To delete multiple Employees' })
269
+ @Directive('@privilege(category: "employee", privilege: "mutation", domainOwnerGranted: true)')
270
+ @Mutation(returns => Boolean, {
271
+ description:
272
+ 'Deletes multiple employee records identified by the given IDs. Also deletes any attachments associated with each employee.'
273
+ })
242
274
  async deleteEmployees(
243
275
  @Arg('ids', type => [String]) ids: string[],
244
276
  @Ctx() context: ResolverContext
245
277
  ): Promise<boolean> {
246
278
  const { domain, tx } = context.state
247
279
 
248
- await tx.getRepository(Employee).delete({
280
+ for (let id of ids) {
281
+ onDeleteEmployeeAsSystemUser(id, context)
282
+ }
283
+
284
+ await getRepository(Employee, tx).delete({
249
285
  domain: { id: domain.id },
250
286
  id: In(ids)
251
287
  })
@@ -256,7 +292,11 @@ export class EmployeeMutation {
256
292
  }
257
293
 
258
294
  @Directive('@transaction')
259
- @Mutation(returns => Boolean, { description: 'To import multiple Employees' })
295
+ @Directive('@privilege(category: "employee", privilege: "mutation", domainOwnerGranted: true)')
296
+ @Mutation(returns => Boolean, {
297
+ description:
298
+ 'Imports multiple employee records into the system. Each employee record must be provided in the EmployeePatch format.'
299
+ })
260
300
  async importEmployees(
261
301
  @Arg('employees', type => [EmployeePatch]) employees: EmployeePatch[],
262
302
  @Ctx() context: ResolverContext
@@ -265,7 +305,7 @@ export class EmployeeMutation {
265
305
 
266
306
  await Promise.all(
267
307
  employees.map(async (employee: EmployeePatch) => {
268
- const createdEmployee: Employee = await tx.getRepository(Employee).save({ domain, ...employee })
308
+ const createdEmployee: Employee = await getRepository(Employee, tx).save({ domain, ...employee })
269
309
  })
270
310
  )
271
311
 
@@ -273,7 +313,11 @@ export class EmployeeMutation {
273
313
  }
274
314
 
275
315
  @Directive('@transaction')
276
- @Mutation(returns => Employee, { description: 'To attach a contact on Employee' })
316
+ @Directive('@privilege(category: "employee", privilege: "mutation", domainOwnerGranted: true)')
317
+ @Mutation(returns => Employee, {
318
+ description:
319
+ 'Attaches an existing contact to an employee. The contact is identified by its ID and the employee is identified by their ID.'
320
+ })
277
321
  async attachContact(
278
322
  @Arg('id') id: string,
279
323
  @Arg('contactId') contactId: string,
@@ -281,12 +325,12 @@ export class EmployeeMutation {
281
325
  ): Promise<Employee> {
282
326
  const { domain, user, tx } = context.state
283
327
 
284
- const employeeRepository = tx.getRepository(Employee)
328
+ const employeeRepository = getRepository(Employee, tx)
285
329
  const employee = await employeeRepository.findOne({
286
330
  where: { domain: { id: domain.id }, id }
287
331
  })
288
332
 
289
- const contactRepository = tx.getRepository(Contact)
333
+ const contactRepository = getRepository(Contact, tx)
290
334
  const contact = await contactRepository.findOne({
291
335
  where: { domain: { id: domain.id }, id: contactId }
292
336
  })
@@ -306,11 +350,14 @@ export class EmployeeMutation {
306
350
  }
307
351
 
308
352
  @Directive('@transaction')
309
- @Mutation(returns => Employee, { description: 'To detach a contact from Employee' })
353
+ @Directive('@privilege(category: "employee", privilege: "mutation", domainOwnerGranted: true)')
354
+ @Mutation(returns => Employee, {
355
+ description: 'Detaches an existing contact from an employee. The employee is identified by their ID.'
356
+ })
310
357
  async detachContact(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Employee> {
311
358
  const { domain, user, tx } = context.state
312
359
 
313
- const repository = tx.getRepository(Employee)
360
+ const repository = getRepository(Employee, tx)
314
361
  const employee = await repository.findOne({
315
362
  where: { domain: { id: domain.id }, id }
316
363
  })
@@ -324,43 +371,16 @@ export class EmployeeMutation {
324
371
  return result
325
372
  }
326
373
 
327
- // @Directive('@privilege')
328
374
  @Directive('@transaction')
329
- @Mutation(returns => Boolean, { description: 'To register employee as a system user' })
375
+ @Directive('@privilege(category: "user", privilege: "mutation", domainOwnerGranted: true)')
376
+ @Mutation(returns => Boolean, {
377
+ description:
378
+ 'Registers an existing employee as a system user, granting them access to the system. The employee is identified by their ID.'
379
+ })
330
380
  async registerEmployeeAsSystemUser(
331
- @Arg('id', { description: 'Employee Id' }) id: string,
381
+ @Arg('employeeId', { description: 'Employee Id' }) employeeId: string,
332
382
  @Ctx() context: ResolverContext
333
383
  ): Promise<boolean> {
334
- const { domain, user, tx } = context.state
335
-
336
- const employeeRepository = tx.getRepository(Employee)
337
- const employee = await employeeRepository.findOne({
338
- where: { domain: { id: domain.id }, id },
339
- relations: ['contact', 'user']
340
- })
341
-
342
- return true
343
-
344
- /*
345
- process
346
-
347
- 0. 이미 연결된 사용자가 없어야 한다.
348
- 1. contact 정보가 있어야 한다.
349
- 2. contact 정보에 대표 email 정보가 있어야 한다.
350
- 3. employee 의 직책 정보가 있어야 한다. => role 과 연결된다.
351
- 4. 사용자 중에서 동일한 이메일을 가진 사용자가 있는가 확인한다.
352
- 5. 그 사용자가 이 도메인에 연결되어 있는 지 확인한다. 없다면 실패.
353
- 6. 직책에 해당하는 역할이 있는 지 확인한다.
354
- 7. 시스템에 사용자를 등록한다.
355
- 8. 역할을 추가한다.
356
- */
357
- // const result = await employeeRepository.save({
358
- // ...employee,
359
- // name: contact.name,
360
- // contact: { id: contactId },
361
- // updater: user
362
- // })
363
-
364
- // return result
384
+ return !!registerEmployeeAsSystemUser(employeeId, context)
365
385
  }
366
386
  }
@@ -1,4 +1,5 @@
1
1
  import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'
2
+ import { GraphQLEmailAddress } from 'graphql-scalars'
2
3
  import { Attachment } from '@things-factory/attachment-base'
3
4
  import { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'
4
5
  import { User } from '@things-factory/auth-base'
@@ -18,9 +19,15 @@ async function getContactItem(contactId: string, type: string, label: string, co
18
19
 
19
20
  return items?.find(item => item.type === type && item.label === label)?.value || ''
20
21
  }
22
+
21
23
  @Resolver(Employee)
22
24
  export class EmployeeQuery {
23
- @Query(returns => Employee!, { nullable: true, description: 'To fetch a Employee' })
25
+ @Directive('@privilege(category: "employee", privilege: "query", domainOwnerGranted: true)')
26
+ @Query(returns => Employee!, {
27
+ nullable: true,
28
+ description:
29
+ 'Fetches a specific employee by their unique ID. Returns the employee object if found, or null if not found.'
30
+ })
24
31
  async employee(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Employee> {
25
32
  const { domain } = context.state
26
33
 
@@ -29,7 +36,11 @@ export class EmployeeQuery {
29
36
  })
30
37
  }
31
38
 
32
- @Query(returns => EmployeeList, { description: 'To fetch multiple Employees' })
39
+ @Directive('@privilege(category: "employee", privilege: "query", domainOwnerGranted: true)')
40
+ @Query(returns => EmployeeList, {
41
+ description:
42
+ 'Fetches a list of employees based on provided query parameters. Supports searching by name, control number, and alias.'
43
+ })
33
44
  async employees(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EmployeeList> {
34
45
  const { domain } = context.state
35
46
 
@@ -45,7 +56,7 @@ export class EmployeeQuery {
45
56
  return { items, total }
46
57
  }
47
58
 
48
- @FieldResolver(type => String)
59
+ @FieldResolver(type => String, { nullable: true })
49
60
  async photo(@Root() employee: Employee): Promise<string | undefined> {
50
61
  const attachment: Attachment = await getRepository(Attachment).findOne({
51
62
  where: {
@@ -58,31 +69,31 @@ export class EmployeeQuery {
58
69
  return attachment?.fullpath
59
70
  }
60
71
 
61
- @FieldResolver(type => String)
72
+ @FieldResolver(type => String, { nullable: true })
62
73
  async phone(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string> {
63
74
  if (!employee.contactId) {
64
75
  return
65
76
  }
66
77
 
67
- await getContactItem(employee.contactId, ContactField.Phone, 'work', context)
78
+ return await getContactItem(employee.contactId, ContactField.Phone, 'work', context)
68
79
  }
69
80
 
70
- @FieldResolver(type => String)
71
- async address(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string> {
81
+ @FieldResolver(type => String, { nullable: true })
82
+ async address(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string | undefined> {
72
83
  if (!employee.contactId) {
73
84
  return
74
85
  }
75
86
 
76
- await getContactItem(employee.contactId, ContactField.Address, 'work', context)
87
+ return await getContactItem(employee.contactId, ContactField.Address, 'work', context)
77
88
  }
78
89
 
79
- @FieldResolver(type => String)
80
- async email(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string> {
90
+ @FieldResolver(type => GraphQLEmailAddress, { nullable: true })
91
+ async email(@Root() employee: Employee, @Ctx() context: ResolverContext): Promise<string | undefined> {
81
92
  if (!employee.contactId) {
82
93
  return
83
94
  }
84
95
 
85
- await getContactItem(employee.contactId, ContactField.Email, 'work', context)
96
+ return await getContactItem(employee.contactId, ContactField.Email, 'work', context)
86
97
  }
87
98
 
88
99
  @FieldResolver(type => Profile)
@@ -91,7 +102,7 @@ export class EmployeeQuery {
91
102
  return
92
103
  }
93
104
 
94
- var contact: Contact = employee.contact
105
+ let contact: Contact = employee.contact
95
106
  if (!contact) {
96
107
  contact = await getRepository(Contact).findOneBy({
97
108
  id: employee.contactId
@@ -5,6 +5,8 @@
5
5
  "button.detach": "detach",
6
6
  "button.edit-detail": "edit detail",
7
7
  "button.edit-contact": "edit contact",
8
+ "button.register-account": "register",
9
+ "field.register-account": "account",
8
10
  "field.approver": "approver",
9
11
  "field.control-no": "control No.",
10
12
  "field.hired-on": "hired on",
@@ -44,5 +46,7 @@
44
46
  "title.department tree": "department hierarchy",
45
47
  "title.contact list": "contact list",
46
48
  "title.organization": "organization",
47
- "title.employees-by-department": "Employees By Department"
49
+ "title.employees-by-department": "Employees By Department",
50
+ "error.employee-already-registered": "This employee is already registered as a system user.",
51
+ "error.contact-information-required": "Contact information is required for this employee."
48
52
  }
@@ -5,6 +5,8 @@
5
5
  "button.detach": "連結解除",
6
6
  "button.edit-contact": "連絡先を編集",
7
7
  "button.edit-detail": "詳細を編集",
8
+ "button.register-account": "アカウント登録",
9
+ "field.register-account": "アカウント登録",
8
10
  "field.approver": "決裁者",
9
11
  "field.control-no": "管理番号",
10
12
  "field.hired-on": "入社日",
@@ -44,5 +46,7 @@
44
46
  "title.department tree": "部署階層図",
45
47
  "title.contact list": "連絡先リスト",
46
48
  "title.organization": "組織",
47
- "title.employees-by-department": "Employees By Department"
49
+ "title.employees-by-department": "部署別の従業員",
50
+ "error.employee-already-registered": "この従業員はすでにシステムユーザーとして登録されています。",
51
+ "error.contact-information-required": "この従業員には連絡先情報が必要です。"
48
52
  }
@@ -5,6 +5,8 @@
5
5
  "button.detach": "연결해제",
6
6
  "button.edit-contact": "연락처 편집",
7
7
  "button.edit-detail": "상세 편집",
8
+ "button.register-account": "계정 등록",
9
+ "field.register-account": "계정 등록",
8
10
  "field.approver": "결재자",
9
11
  "field.control-no": "관리 번호",
10
12
  "field.hired-on": "입사일",
@@ -44,5 +46,7 @@
44
46
  "title.department tree": "부서 조직도",
45
47
  "title.contact list": "연락처 관리",
46
48
  "title.organization": "조직",
47
- "title.employees-by-department": "부서별 직원"
49
+ "title.employees-by-department": "부서별 직원",
50
+ "error.employee-already-registered": "해당 직원은 이미 시스템 사용자로 등록되어 있습니다.",
51
+ "error.contact-information-required": "해당 직원의 연락처 정보가 필요합니다."
48
52
  }