@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.
- package/client/component/department-selector.ts +7 -2
- package/client/pages/employee/employee-list-page.ts +39 -5
- package/dist-client/component/department-selector.d.ts +1 -1
- package/dist-client/component/department-selector.js +6 -2
- package/dist-client/component/department-selector.js.map +1 -1
- package/dist-client/pages/employee/employee-list-page.d.ts +1 -0
- package/dist-client/pages/employee/employee-list-page.js +36 -5
- package/dist-client/pages/employee/employee-list-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/register-employee-as-system-user.d.ts +5 -1
- package/dist-server/controllers/register-employee-as-system-user.js +87 -35
- package/dist-server/controllers/register-employee-as-system-user.js.map +1 -1
- package/dist-server/service/employee/employee-mutation.d.ts +1 -1
- package/dist-server/service/employee/employee-mutation.js +68 -60
- package/dist-server/service/employee/employee-mutation.js.map +1 -1
- package/dist-server/service/employee/employee-query.d.ts +2 -2
- package/dist-server/service/employee/employee-query.js +18 -10
- package/dist-server/service/employee/employee-query.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/server/controllers/register-employee-as-system-user.ts +111 -37
- package/server/service/employee/employee-mutation.ts +83 -63
- package/server/service/employee/employee-query.ts +23 -12
- package/translations/en.json +5 -1
- package/translations/ja.json +5 -1
- package/translations/ko.json +5 -1
- package/translations/ms.json +4 -1
- 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.
|
|
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.
|
|
37
|
-
"@things-factory/code-ui": "^7.0.
|
|
38
|
-
"@things-factory/contact": "^7.0.
|
|
39
|
-
"@things-factory/shell": "^7.0.
|
|
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": "
|
|
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
|
|
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
|
-
|
|
34
|
-
|
|
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
|
|
37
|
-
|
|
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
|
-
|
|
51
|
+
id,
|
|
52
|
+
domain: { id: domain.id }
|
|
40
53
|
},
|
|
41
|
-
relations: ['
|
|
54
|
+
relations: ['contact', 'user']
|
|
42
55
|
})
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
74
|
+
if (lastJobResponsibility) {
|
|
75
|
+
const lastRole = await getRepository(Role, tx).findOne({
|
|
76
|
+
where: { name: lastJobResponsibility, domain: { id: domain.id } }
|
|
77
|
+
})
|
|
50
78
|
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
106
|
+
id: employeeId,
|
|
55
107
|
domain: { id: domain.id }
|
|
56
|
-
}
|
|
108
|
+
},
|
|
109
|
+
relations: ['user']
|
|
57
110
|
})
|
|
58
111
|
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
@
|
|
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
|
|
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
|
|
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
|
|
42
|
+
? employee.user && (await getRepository(User, tx).findOneBy({ id: employee.user.id }))
|
|
32
43
|
: undefined
|
|
33
44
|
|
|
34
|
-
const result = await
|
|
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
|
-
@
|
|
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
|
|
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
|
|
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
|
|
96
|
+
'user' in patch ? patch.user && (await getRepository(User, tx).findOneBy({ id: patch.user.id })) : undefined
|
|
82
97
|
|
|
83
|
-
const repository =
|
|
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
|
-
@
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
@
|
|
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
|
-
|
|
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
|
-
@
|
|
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
|
-
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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 =
|
|
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 =
|
|
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
|
-
@
|
|
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 =
|
|
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
|
-
@
|
|
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('
|
|
381
|
+
@Arg('employeeId', { description: 'Employee Id' }) employeeId: string,
|
|
332
382
|
@Ctx() context: ResolverContext
|
|
333
383
|
): Promise<boolean> {
|
|
334
|
-
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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 =>
|
|
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
|
-
|
|
105
|
+
let contact: Contact = employee.contact
|
|
95
106
|
if (!contact) {
|
|
96
107
|
contact = await getRepository(Contact).findOneBy({
|
|
97
108
|
id: employee.contactId
|
package/translations/en.json
CHANGED
|
@@ -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
|
}
|
package/translations/ja.json
CHANGED
|
@@ -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
|
}
|
package/translations/ko.json
CHANGED
|
@@ -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
|
}
|