@things-factory/organization 8.0.0-beta.8 → 8.0.0

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 (94) hide show
  1. package/client/bootstrap.ts +23 -0
  2. package/client/component/approval-line-brief.ts +119 -0
  3. package/client/component/approval-line-items-editor-popup.ts +91 -0
  4. package/client/component/approval-line-items-editor.ts +325 -0
  5. package/client/component/approval-line-selector.ts +235 -0
  6. package/client/component/approval-line-templates-manager.ts +229 -0
  7. package/client/component/approval-line-view.ts +122 -0
  8. package/client/component/assignees-editor-popup.ts +79 -0
  9. package/client/component/assignees-editor.ts +217 -0
  10. package/client/component/assignees-view.ts +55 -0
  11. package/client/component/department-selector.ts +151 -0
  12. package/client/component/department-view.ts +107 -0
  13. package/client/component/index.ts +16 -0
  14. package/client/component/recipients-editor-popup.ts +79 -0
  15. package/client/component/recipients-editor.ts +212 -0
  16. package/client/component/recipients-view.ts +55 -0
  17. package/client/grist-editor/grist-editor-approval-line.ts +70 -0
  18. package/client/grist-editor/grist-editor-assignees.ts +69 -0
  19. package/client/grist-editor/grist-editor-department-object.ts +78 -0
  20. package/client/grist-editor/grist-editor-recipients.ts +69 -0
  21. package/client/grist-editor/grist-renderer-approval-line.ts +13 -0
  22. package/client/grist-editor/grist-renderer-assignees.ts +13 -0
  23. package/client/grist-editor/grist-renderer-department-object.ts +13 -0
  24. package/client/grist-editor/grist-renderer-recipients.ts +13 -0
  25. package/client/index.ts +2 -0
  26. package/client/pages/approval-line/common-approval-line-templates-page.ts +382 -0
  27. package/client/pages/approval-line/my-approval-line-templates-page.ts +385 -0
  28. package/client/pages/department/department-importer.ts +87 -0
  29. package/client/pages/department/department-list-page.ts +450 -0
  30. package/client/pages/department/department-tree-page.ts +379 -0
  31. package/client/pages/employee/employee-importer.ts +87 -0
  32. package/client/pages/employee/employee-list-page.ts +772 -0
  33. package/client/pages/employee/employees-by-department.ts +519 -0
  34. package/client/route.ts +27 -0
  35. package/client/tsconfig.json +13 -0
  36. package/client/types/approval-line.ts +52 -0
  37. package/client/types/contact.ts +51 -0
  38. package/client/types/department.ts +29 -0
  39. package/client/types/employee.ts +50 -0
  40. package/client/types/index.ts +5 -0
  41. package/client/types/org-member.ts +27 -0
  42. package/dist-client/bootstrap.js +1 -8
  43. package/dist-client/bootstrap.js.map +1 -1
  44. package/dist-client/pages/employee/employee-list-page.js +3 -3
  45. package/dist-client/pages/employee/employee-list-page.js.map +1 -1
  46. package/dist-client/pages/employee/employees-by-department.js +2 -2
  47. package/dist-client/pages/employee/employees-by-department.js.map +1 -1
  48. package/dist-client/tsconfig.tsbuildinfo +1 -1
  49. package/dist-server/service/employee/employee-history.d.ts +2 -6
  50. package/dist-server/service/employee/employee-history.js +3 -23
  51. package/dist-server/service/employee/employee-history.js.map +1 -1
  52. package/dist-server/service/employee/employee-query.js +1 -1
  53. package/dist-server/service/employee/employee-query.js.map +1 -1
  54. package/dist-server/service/employee/employee-type.d.ts +5 -13
  55. package/dist-server/service/employee/employee-type.js +7 -39
  56. package/dist-server/service/employee/employee-type.js.map +1 -1
  57. package/dist-server/service/employee/employee.d.ts +2 -6
  58. package/dist-server/service/employee/employee.js +3 -23
  59. package/dist-server/service/employee/employee.js.map +1 -1
  60. package/dist-server/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +12 -12
  62. package/server/controllers/register-employee-as-system-user.ts +136 -0
  63. package/server/index.ts +3 -0
  64. package/server/migrations/1723861013111-seed-organization-codes.ts +127 -0
  65. package/server/migrations/index.ts +9 -0
  66. package/server/routes.ts +26 -0
  67. package/server/service/approval-line/approval-line-item.ts +42 -0
  68. package/server/service/approval-line/approval-line-mutation.ts +394 -0
  69. package/server/service/approval-line/approval-line-query.ts +208 -0
  70. package/server/service/approval-line/approval-line-type.ts +63 -0
  71. package/server/service/approval-line/approval-line.ts +123 -0
  72. package/server/service/approval-line/index.ts +7 -0
  73. package/server/service/department/department-history.ts +141 -0
  74. package/server/service/department/department-mutation.ts +231 -0
  75. package/server/service/department/department-query.ts +131 -0
  76. package/server/service/department/department-type.ts +74 -0
  77. package/server/service/department/department.ts +116 -0
  78. package/server/service/department/event-subscriber.ts +17 -0
  79. package/server/service/department/index.ts +9 -0
  80. package/server/service/employee/employee-history.ts +173 -0
  81. package/server/service/employee/employee-mutation.ts +386 -0
  82. package/server/service/employee/employee-query.ts +172 -0
  83. package/server/service/employee/employee-type.ts +176 -0
  84. package/server/service/employee/employee.ts +177 -0
  85. package/server/service/employee/event-subscriber.ts +17 -0
  86. package/server/service/employee/index.ts +9 -0
  87. package/server/service/index.ts +39 -0
  88. package/server/tsconfig.json +10 -0
  89. package/dist-client/filters-form/filter-department-object.d.ts +0 -3
  90. package/dist-client/filters-form/filter-department-object.js +0 -8
  91. package/dist-client/filters-form/filter-department-object.js.map +0 -1
  92. package/dist-client/filters-form/ox-filter-department-object.d.ts +0 -15
  93. package/dist-client/filters-form/ox-filter-department-object.js +0 -130
  94. package/dist-client/filters-form/ox-filter-department-object.js.map +0 -1
@@ -0,0 +1,123 @@
1
+ import {
2
+ CreateDateColumn,
3
+ UpdateDateColumn,
4
+ DeleteDateColumn,
5
+ Entity,
6
+ Index,
7
+ Column,
8
+ RelationId,
9
+ ManyToOne,
10
+ PrimaryGeneratedColumn,
11
+ VersionColumn
12
+ } from 'typeorm'
13
+ import { InputType, ObjectType, Field, Int, ID, registerEnumType } from 'type-graphql'
14
+
15
+ import { Domain, ObjectRef } from '@things-factory/shell'
16
+ import { Role, User } from '@things-factory/auth-base'
17
+
18
+ import { ApprovalLineItem } from './approval-line-item'
19
+ import { Employee } from '../employee/employee'
20
+ import { Department } from '../department/department'
21
+
22
+ export * from './approval-line-item'
23
+
24
+ export enum ApprovalLineOwnerType {
25
+ Employee = 'Employee',
26
+ Common = 'Common'
27
+ }
28
+
29
+ registerEnumType(ApprovalLineOwnerType, {
30
+ name: 'ApprovalLineOwnerType',
31
+ description: 'type enumeration of a approvalLineOwner'
32
+ })
33
+
34
+ @ObjectType()
35
+ export class ApprovalLineOwner {
36
+ @Field(() => ID, { description: 'Field id' })
37
+ id: string
38
+
39
+ @Field({ nullable: true, description: 'Field name' })
40
+ name?: string
41
+
42
+ @Field({ nullable: true, description: 'Field description' })
43
+ description?: string
44
+
45
+ @Field({ nullable: true })
46
+ controlNo?: string
47
+ }
48
+
49
+ @Entity()
50
+ @Index(
51
+ 'ix_approval_line_0',
52
+ (approvalLine: ApprovalLine) => [
53
+ approvalLine.domain,
54
+ approvalLine.ownerType,
55
+ approvalLine.ownerValue,
56
+ approvalLine.name
57
+ ],
58
+ {
59
+ unique: true
60
+ }
61
+ )
62
+ @ObjectType({ description: 'Entity for ApprovalLine' })
63
+ export class ApprovalLine {
64
+ @PrimaryGeneratedColumn('uuid')
65
+ @Field(type => ID)
66
+ readonly id: string
67
+
68
+ @ManyToOne(type => Domain)
69
+ @Field(type => Domain)
70
+ domain?: Domain
71
+
72
+ @RelationId((approvalLine: ApprovalLine) => approvalLine.domain)
73
+ domainId?: string
74
+
75
+ @Column()
76
+ @Field({ nullable: true })
77
+ name?: string
78
+
79
+ @Column({ nullable: true })
80
+ @Field({ nullable: true })
81
+ description?: string
82
+
83
+ @Column('simple-json', { nullable: true })
84
+ @Field(type => [ApprovalLineItem], { nullable: true })
85
+ model?: ApprovalLineItem[]
86
+
87
+ @Column({ nullable: true, length: 20 })
88
+ @Field({ nullable: true })
89
+ ownerType?: ApprovalLineOwnerType
90
+
91
+ @Column({ nullable: true })
92
+ @Field({ nullable: true })
93
+ ownerValue?: string
94
+
95
+ @ManyToOne(type => Employee, employee => employee.approvalLines, { nullable: true })
96
+ @Field({ nullable: true })
97
+ ownerEmployee?: Employee
98
+
99
+ @Field(type => ApprovalLineOwner, { nullable: true })
100
+ owner?: ApprovalLineOwner
101
+
102
+ @CreateDateColumn()
103
+ @Field({ nullable: true })
104
+ createdAt?: Date
105
+
106
+ @UpdateDateColumn()
107
+ @Field({ nullable: true })
108
+ updatedAt?: Date
109
+
110
+ @ManyToOne(type => User, { nullable: true })
111
+ @Field(type => User, { nullable: true })
112
+ creator?: User
113
+
114
+ @RelationId((approvalLine: ApprovalLine) => approvalLine.creator)
115
+ creatorId?: string
116
+
117
+ @ManyToOne(type => User, { nullable: true })
118
+ @Field(type => User, { nullable: true })
119
+ updater?: User
120
+
121
+ @RelationId((approvalLine: ApprovalLine) => approvalLine.updater)
122
+ updaterId?: string
123
+ }
@@ -0,0 +1,7 @@
1
+ import { ApprovalLine } from './approval-line'
2
+ import { ApprovalLineQuery } from './approval-line-query'
3
+ import { ApprovalLineMutation } from './approval-line-mutation'
4
+
5
+ export const entities = [ApprovalLine]
6
+ export const resolvers = [ApprovalLineQuery, ApprovalLineMutation]
7
+ export const subscribers = []
@@ -0,0 +1,141 @@
1
+ import { Field, ID, ObjectType } from 'type-graphql'
2
+ import { Column, Entity, Index, ManyToOne, OneToMany, PrimaryGeneratedColumn, RelationId } from 'typeorm'
3
+
4
+ import {
5
+ HistoryActionColumn,
6
+ HistoryActionType,
7
+ HistoryEntityInterface,
8
+ HistoryOriginalIdColumn
9
+ } from '@operato/typeorm-history'
10
+ import { Role, User } from '@things-factory/auth-base'
11
+ import { config } from '@things-factory/env'
12
+ import { Domain } from '@things-factory/shell'
13
+
14
+ import { Department } from './department'
15
+ import { Employee } from '../employee/employee'
16
+
17
+ const ORMCONFIG = config.get('ormconfig', {})
18
+ const DATABASE_TYPE = ORMCONFIG.type
19
+
20
+ @Entity()
21
+ @Index(
22
+ 'ix_department_history_0',
23
+ (departmentHistory: DepartmentHistory) => [departmentHistory.originalId, departmentHistory.version],
24
+ { unique: true }
25
+ )
26
+ @Index(
27
+ 'ix_department_history_1',
28
+ (departmentHistory: DepartmentHistory) => [
29
+ departmentHistory.domain,
30
+ departmentHistory.originalId,
31
+ departmentHistory.version
32
+ ],
33
+ {
34
+ unique: true
35
+ }
36
+ )
37
+ @ObjectType({ description: 'History Entity of Department' })
38
+ export class DepartmentHistory implements HistoryEntityInterface<Department> {
39
+ @PrimaryGeneratedColumn('uuid')
40
+ @Field(type => ID)
41
+ readonly id: string
42
+
43
+ @Column({ nullable: true, default: 1 })
44
+ @Field({ nullable: true })
45
+ version?: number = 1
46
+
47
+ @ManyToOne(type => Domain)
48
+ @Field(type => Domain)
49
+ domain?: Domain
50
+
51
+ @RelationId((department: Department) => department.domain)
52
+ domainId?: string
53
+
54
+ @Column()
55
+ @Field()
56
+ controlNo: string
57
+
58
+ @Column()
59
+ @Field({ nullable: true })
60
+ name?: string
61
+
62
+ @Column({ nullable: true })
63
+ @Field({ nullable: true })
64
+ description?: string
65
+
66
+ @ManyToOne(type => Department, department => department.children, { nullable: true })
67
+ @Field({ nullable: true })
68
+ parent?: Department
69
+
70
+ @RelationId((department: Department) => department.parent)
71
+ parentId?: string
72
+
73
+ @OneToMany(type => Department, department => department.parent)
74
+ @Field(type => [Department])
75
+ children?: Department[]
76
+
77
+ @ManyToOne(type => Employee, manager => manager.manages, { nullable: true })
78
+ @Field({ nullable: true })
79
+ manager?: Employee
80
+
81
+ @RelationId((department: Department) => department.manager)
82
+ managerId?: string
83
+
84
+ @Column({ nullable: true })
85
+ @Field({ nullable: true })
86
+ active?: boolean
87
+
88
+ @Column({ nullable: true })
89
+ @Field({ nullable: true })
90
+ extension?: string
91
+
92
+ @Column({ nullable: true })
93
+ @Field({ nullable: true })
94
+ createdAt?: Date
95
+
96
+ @Column({ nullable: true })
97
+ @Field({ nullable: true })
98
+ updatedAt?: Date
99
+
100
+ @Column({ nullable: true })
101
+ @Field({ nullable: true })
102
+ deletedAt?: Date
103
+
104
+ @ManyToOne(type => User, { nullable: true })
105
+ @Field(type => User, { nullable: true })
106
+ creator?: User
107
+
108
+ @RelationId((department: Department) => department.creator)
109
+ creatorId?: string
110
+
111
+ @ManyToOne(type => User, { nullable: true })
112
+ @Field(type => User, { nullable: true })
113
+ updater?: User
114
+
115
+ @RelationId((department: Department) => department.updater)
116
+ updaterId?: string
117
+
118
+ @Field(type => String, { nullable: true })
119
+ picture?: string
120
+
121
+ @HistoryOriginalIdColumn()
122
+ public originalId!: string
123
+
124
+ @HistoryActionColumn({
125
+ nullable: false,
126
+ type:
127
+ DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
128
+ ? 'enum'
129
+ : DATABASE_TYPE == 'oracle'
130
+ ? 'varchar2'
131
+ : DATABASE_TYPE == 'mssql'
132
+ ? 'nvarchar'
133
+ : 'varchar',
134
+ enum:
135
+ DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
136
+ ? HistoryActionType
137
+ : undefined,
138
+ length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined : 10
139
+ })
140
+ public action!: HistoryActionType
141
+ }
@@ -0,0 +1,231 @@
1
+ import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
+ import { In } from 'typeorm'
3
+
4
+ import { getRepository } from '@things-factory/shell'
5
+ import { createAttachment, deleteAttachmentsByRef } from '@things-factory/attachment-base'
6
+
7
+ import { Department } from './department'
8
+ import { NewDepartment, DepartmentPatch } from './department-type'
9
+ import { Employee } from '../employee/employee'
10
+
11
+ @Resolver(Department)
12
+ export class DepartmentMutation {
13
+ @Directive('@transaction')
14
+ @Directive('@privilege(category: "department", privilege: "mutation", domainOwnerGranted: true)')
15
+ @Mutation(returns => Department, { description: 'To create new Department' })
16
+ async createDepartment(
17
+ @Arg('department') department: NewDepartment,
18
+ @Ctx() context: ResolverContext
19
+ ): Promise<Department> {
20
+ const { domain, user, tx } = context.state
21
+
22
+ const manager =
23
+ 'manager' in department
24
+ ? department.manager && (await getRepository(Employee, tx).findOneBy({ id: department.manager.id }))
25
+ : undefined
26
+
27
+ const result = await getRepository(Department, tx).save({
28
+ ...department,
29
+ domain,
30
+ manager,
31
+ creator: user,
32
+ updater: user
33
+ })
34
+
35
+ if (department.picture) {
36
+ await createAttachment(
37
+ null,
38
+ {
39
+ attachment: {
40
+ file: department.picture,
41
+ refType: Department.name,
42
+ refBy: result.id
43
+ }
44
+ },
45
+ context
46
+ )
47
+ }
48
+
49
+ return result
50
+ }
51
+
52
+ @Directive('@transaction')
53
+ @Directive('@privilege(category: "department", privilege: "mutation", domainOwnerGranted: true)')
54
+ @Mutation(returns => Department, { description: 'To modify Department information' })
55
+ async updateDepartment(
56
+ @Arg('id') id: string,
57
+ @Arg('patch') patch: DepartmentPatch,
58
+ @Ctx() context: ResolverContext
59
+ ): Promise<Department> {
60
+ const { domain, user, tx } = context.state
61
+
62
+ const repository = getRepository(Department, tx)
63
+ const department = await repository.findOne({
64
+ where: { domain: { id: domain.id }, id }
65
+ })
66
+
67
+ const manager =
68
+ 'manager' in patch
69
+ ? patch.manager && (await getRepository(Employee, tx).findOneBy({ id: patch.manager.id }))
70
+ : undefined
71
+
72
+ const result = await repository.save({
73
+ ...department,
74
+ ...patch,
75
+ manager,
76
+ updater: user
77
+ })
78
+
79
+ if (patch.picture) {
80
+ await deleteAttachmentsByRef(null, { refBys: [result.id] }, context)
81
+ await createAttachment(
82
+ null,
83
+ {
84
+ attachment: {
85
+ file: patch.picture,
86
+ refType: Department.name,
87
+ refBy: result.id
88
+ }
89
+ },
90
+ context
91
+ )
92
+ }
93
+
94
+ return result
95
+ }
96
+
97
+ @Directive('@transaction')
98
+ @Directive('@privilege(category: "department", privilege: "mutation", domainOwnerGranted: true)')
99
+ @Mutation(returns => [Department], { description: "To modify multiple Departments' information" })
100
+ async updateMultipleDepartment(
101
+ @Arg('patches', type => [DepartmentPatch]) patches: DepartmentPatch[],
102
+ @Ctx() context: ResolverContext
103
+ ): Promise<Department[]> {
104
+ const { domain, user, tx } = context.state
105
+
106
+ let results = []
107
+ const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
108
+ const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
109
+ const departmentRepo = getRepository(Department, tx)
110
+
111
+ if (_createRecords.length > 0) {
112
+ for (let i = 0; i < _createRecords.length; i++) {
113
+ const newRecord = _createRecords[i]
114
+ const manager =
115
+ 'manager' in newRecord
116
+ ? newRecord.manager && (await getRepository(Employee, tx).findOneBy({ id: newRecord.manager.id }))
117
+ : undefined
118
+
119
+ const result = await departmentRepo.save({
120
+ ...newRecord,
121
+ manager,
122
+ domain,
123
+ creator: user,
124
+ updater: user
125
+ })
126
+
127
+ if (newRecord.picture) {
128
+ await createAttachment(
129
+ null,
130
+ {
131
+ attachment: {
132
+ file: newRecord.picture,
133
+ refType: Department.name,
134
+ refBy: result.id
135
+ }
136
+ },
137
+ context
138
+ )
139
+ }
140
+
141
+ results.push({ ...result, cuFlag: '+' })
142
+ }
143
+ }
144
+
145
+ if (_updateRecords.length > 0) {
146
+ for (let i = 0; i < _updateRecords.length; i++) {
147
+ const updateRecord = _updateRecords[i]
148
+ const department = await departmentRepo.findOneBy({ id: updateRecord.id })
149
+ const manager =
150
+ 'manager' in updateRecord
151
+ ? updateRecord.manager && (await getRepository(Employee, tx).findOneBy({ id: updateRecord.manager.id }))
152
+ : undefined
153
+
154
+ const result = await departmentRepo.save({
155
+ ...department,
156
+ ...updateRecord,
157
+ manager,
158
+ updater: user
159
+ })
160
+
161
+ if (updateRecord.picture) {
162
+ await deleteAttachmentsByRef(null, { refBys: [result.id] }, context)
163
+ await createAttachment(
164
+ null,
165
+ {
166
+ attachment: {
167
+ file: updateRecord.picture,
168
+ refType: Department.name,
169
+ refBy: result.id
170
+ }
171
+ },
172
+ context
173
+ )
174
+ }
175
+
176
+ results.push({ ...result, cuFlag: 'M' })
177
+ }
178
+ }
179
+
180
+ return results
181
+ }
182
+
183
+ @Directive('@transaction')
184
+ @Directive('@privilege(category: "department", privilege: "mutation", domainOwnerGranted: true)')
185
+ @Mutation(returns => Boolean, { description: 'To delete Department' })
186
+ async deleteDepartment(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
187
+ const { domain, tx } = context.state
188
+
189
+ await getRepository(Department, tx).softDelete({ domain: { id: domain.id }, id })
190
+ // await deleteAttachmentsByRef(null, { refBys: [id] }, context)
191
+
192
+ return true
193
+ }
194
+
195
+ @Directive('@transaction')
196
+ @Directive('@privilege(category: "department", privilege: "mutation", domainOwnerGranted: true)')
197
+ @Mutation(returns => Boolean, { description: 'To delete multiple Departments' })
198
+ async deleteDepartments(
199
+ @Arg('ids', type => [String]) ids: string[],
200
+ @Ctx() context: ResolverContext
201
+ ): Promise<boolean> {
202
+ const { domain, tx } = context.state
203
+
204
+ await getRepository(Department, tx).softDelete({
205
+ domain: { id: domain.id },
206
+ id: In(ids)
207
+ })
208
+
209
+ // await deleteAttachmentsByRef(null, { refBys: ids }, context)
210
+
211
+ return true
212
+ }
213
+
214
+ @Directive('@transaction')
215
+ @Directive('@privilege(category: "department", privilege: "mutation", domainOwnerGranted: true)')
216
+ @Mutation(returns => Boolean, { description: 'To import multiple Departments' })
217
+ async importDepartments(
218
+ @Arg('departments', type => [DepartmentPatch]) departments: DepartmentPatch[],
219
+ @Ctx() context: ResolverContext
220
+ ): Promise<boolean> {
221
+ const { domain, tx } = context.state
222
+
223
+ await Promise.all(
224
+ departments.map(async (department: DepartmentPatch) => {
225
+ const createdDepartment: Department = await getRepository(Department, tx).save({ domain, ...department })
226
+ })
227
+ )
228
+
229
+ return true
230
+ }
231
+ }
@@ -0,0 +1,131 @@
1
+ import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'
2
+ import { IsNull } from 'typeorm'
3
+ import { Attachment } from '@things-factory/attachment-base'
4
+ import { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'
5
+ import { User } from '@things-factory/auth-base'
6
+ import { Department } from './department'
7
+ import { DepartmentList } from './department-type'
8
+ import { Employee } from '../employee/employee'
9
+
10
+ @Resolver(Department)
11
+ export class DepartmentQuery {
12
+ @Directive('@privilege(category: "department", privilege: "query", domainOwnerGranted: true)')
13
+ @Query(returns => DepartmentList, { nullable: true, description: 'To fetch a Root Departments' })
14
+ async departmentRoots(
15
+ @Args(type => ListParam) params: ListParam,
16
+ @Ctx() context: ResolverContext
17
+ ): Promise<DepartmentList> {
18
+ const { domain } = context.state
19
+
20
+ const queryBuilder = getQueryBuilderFromListParams({
21
+ domain,
22
+ params,
23
+ repository: await getRepository(Department),
24
+ searchables: ['name', 'description', 'controlNo']
25
+ }).andWhere({ domain: { id: domain.id }, parent: { id: IsNull() } })
26
+
27
+ const [items, total] = await queryBuilder.getManyAndCount()
28
+
29
+ return { items, total }
30
+ }
31
+
32
+ @Directive('@privilege(category: "department", privilege: "query", domainOwnerGranted: true)')
33
+ @Query(returns => Department!, { nullable: true, description: 'To fetch a Department' })
34
+ async department(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Department> {
35
+ const { domain } = context.state
36
+
37
+ return await getRepository(Department).findOne({
38
+ where: { domain: { id: domain.id }, id }
39
+ })
40
+ }
41
+
42
+ @Directive('@privilege(category: "department", privilege: "query", domainOwnerGranted: true)')
43
+ @Query(returns => DepartmentList, { description: 'To fetch multiple Departments' })
44
+ async departments(
45
+ @Args(type => ListParam) params: ListParam,
46
+ @Ctx() context: ResolverContext
47
+ ): Promise<DepartmentList> {
48
+ const { domain } = context.state
49
+
50
+ const queryBuilder = getQueryBuilderFromListParams({
51
+ domain,
52
+ params,
53
+ repository: await getRepository(Department),
54
+ searchables: ['name', 'description', 'controlNo']
55
+ })
56
+
57
+ const [items, total] = await queryBuilder.getManyAndCount()
58
+
59
+ return { items, total }
60
+ }
61
+
62
+ @FieldResolver(type => Employee)
63
+ async manager(@Root() department: Department): Promise<Employee> {
64
+ return (
65
+ department.managerId &&
66
+ (await getRepository(Employee).findOneBy({
67
+ id: department.managerId
68
+ }))
69
+ )
70
+ }
71
+
72
+ @FieldResolver(type => Department)
73
+ async parent(@Root() department: Department): Promise<Department> {
74
+ return (
75
+ department.parentId &&
76
+ (await getRepository(Department).findOneBy({
77
+ id: department.parentId
78
+ }))
79
+ )
80
+ }
81
+
82
+ @FieldResolver(type => [Department])
83
+ async children(
84
+ @Root() department: Department,
85
+ @Args(type => ListParam) params: ListParam,
86
+ @Ctx() context: ResolverContext
87
+ ): Promise<Department[]> {
88
+ const { domain } = context.state
89
+
90
+ const queryBuilder = getQueryBuilderFromListParams({
91
+ domain,
92
+ params,
93
+ repository: await getRepository(Department),
94
+ searchables: ['name', 'description', 'controlNo']
95
+ }).andWhere({
96
+ parent: { id: department.id }
97
+ })
98
+
99
+ const [items, total] = await queryBuilder.getManyAndCount()
100
+
101
+ return items
102
+ }
103
+
104
+ @FieldResolver(type => String)
105
+ async picture(@Root() department: Department): Promise<string | undefined> {
106
+ const attachment: Attachment = await getRepository(Attachment).findOne({
107
+ where: {
108
+ domain: { id: department.domainId },
109
+ refType: Department.name,
110
+ refBy: department.id
111
+ }
112
+ })
113
+
114
+ return attachment?.fullpath
115
+ }
116
+
117
+ @FieldResolver(type => Domain)
118
+ async domain(@Root() department: Department): Promise<Domain> {
119
+ return await getRepository(Domain).findOneBy({ id: department.domainId })
120
+ }
121
+
122
+ @FieldResolver(type => User)
123
+ async updater(@Root() department: Department): Promise<User> {
124
+ return await getRepository(User).findOneBy({ id: department.updaterId })
125
+ }
126
+
127
+ @FieldResolver(type => User)
128
+ async creator(@Root() department: Department): Promise<User> {
129
+ return await getRepository(User).findOneBy({ id: department.creatorId })
130
+ }
131
+ }
@@ -0,0 +1,74 @@
1
+ import type { FileUpload } from 'graphql-upload/GraphQLUpload.js'
2
+ import GraphQLUpload from 'graphql-upload/GraphQLUpload.js'
3
+ import { ObjectType, Field, InputType, Int, ID, registerEnumType } from 'type-graphql'
4
+
5
+ import { ObjectRef, ScalarObject } from '@things-factory/shell'
6
+
7
+ import { Department } from './department'
8
+ import { ObjectRefForEmployee } from '../employee/employee-type'
9
+
10
+ @InputType()
11
+ export class NewDepartment {
12
+ @Field()
13
+ controlNo: string
14
+
15
+ @Field()
16
+ name: string
17
+
18
+ @Field({ nullable: true })
19
+ description?: string
20
+
21
+ @Field({ nullable: true })
22
+ active?: boolean
23
+
24
+ @Field({ nullable: true })
25
+ extension?: string
26
+
27
+ @Field(type => GraphQLUpload, { nullable: true })
28
+ picture?: FileUpload
29
+
30
+ @Field(type => ObjectRef, { nullable: true })
31
+ parent?: ObjectRef
32
+
33
+ @Field(type => ObjectRefForEmployee, { nullable: true })
34
+ manager?: ObjectRefForEmployee
35
+ }
36
+
37
+ @InputType()
38
+ export class DepartmentPatch {
39
+ @Field(type => ID, { nullable: true })
40
+ id?: string
41
+
42
+ @Field({ nullable: true })
43
+ controlNo?: string
44
+
45
+ @Field({ nullable: true })
46
+ name?: string
47
+
48
+ @Field({ nullable: true })
49
+ description?: string
50
+
51
+ @Field({ nullable: true })
52
+ active?: boolean
53
+
54
+ @Field(type => GraphQLUpload, { nullable: true })
55
+ picture?: FileUpload
56
+
57
+ @Field(type => ObjectRef, { nullable: true })
58
+ parent?: ObjectRef
59
+
60
+ @Field(type => ObjectRefForEmployee, { nullable: true })
61
+ manager?: ObjectRefForEmployee
62
+
63
+ @Field({ nullable: true })
64
+ cuFlag?: string
65
+ }
66
+
67
+ @ObjectType()
68
+ export class DepartmentList {
69
+ @Field(type => [Department])
70
+ items: Department[]
71
+
72
+ @Field(type => Int)
73
+ total: number
74
+ }