@platform-modules/foreign-ministry 1.1.16 → 1.1.18
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/HELPDESK_SCHEMA_DESIGN.md +479 -0
- package/dist/data-source.js +15 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/models/IssueTypesModel.d.ts +14 -0
- package/dist/models/IssueTypesModel.js +66 -0
- package/dist/models/LeaveApprovalsModel.d.ts +2 -1
- package/dist/models/LeaveApprovalsModel.js +1 -0
- package/dist/models/RoutingGroupsModel.d.ts +19 -0
- package/dist/models/RoutingGroupsModel.js +85 -0
- package/dist/models/ServiceApprovalsModel.d.ts +23 -0
- package/dist/models/ServiceApprovalsModel.js +91 -0
- package/dist/models/ServiceAttachmentsModel.d.ts +10 -0
- package/dist/models/ServiceAttachmentsModel.js +56 -0
- package/dist/models/ServiceChatsModel.d.ts +9 -0
- package/dist/models/ServiceChatsModel.js +51 -0
- package/dist/models/ServiceRequestsModel.d.ts +36 -0
- package/dist/models/ServiceRequestsModel.js +136 -0
- package/dist/models/ServiceWorkFlowModel.d.ts +19 -0
- package/dist/models/ServiceWorkFlowModel.js +71 -0
- package/package.json +1 -1
- package/src/data-source.ts +14 -0
- package/src/index.ts +7 -0
- package/src/models/IssueTypesModel.ts +50 -0
- package/src/models/LeaveApprovalsModel.ts +2 -1
- package/src/models/RoutingGroupsModel.ts +66 -0
- package/src/models/ServiceApprovalsModel.ts +76 -0
- package/src/models/ServiceAttachmentsModel.ts +43 -0
- package/src/models/ServiceChatsModel.ts +39 -0
- package/src/models/ServiceRequestsModel.ts +111 -0
- package/src/models/ServiceWorkFlowModel.ts +57 -0
- package/dist/models/LeaveApprovalDetailsModel.d.ts +0 -13
- package/dist/models/LeaveApprovalDetailsModel.js +0 -51
- package/dist/models/LeaveApprovalMatrixModel.d.ts +0 -7
- package/dist/models/LeaveApprovalMatrixModel.js +0 -40
- package/dist/models/UpdateAttendenceRequestModel.d.ts +0 -28
- package/dist/models/UpdateAttendenceRequestModel.js +0 -86
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# Helpdesk Service Schema Design
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
This document outlines the schema design for the Helpdesk Service, which routes tickets based on Category (service), Subcategory (sub_service), and Issue Type, with automatic group assignment for routing.
|
|
5
|
+
|
|
6
|
+
## Business Requirements
|
|
7
|
+
1. **UI Selection**: User selects Category → Subcategory → Issue Type
|
|
8
|
+
2. **Auto-Routing**: Group Name auto-populated based on selection
|
|
9
|
+
3. **Role-Based Access**: HOD, HOS, and other roles determine who can view/approve requests
|
|
10
|
+
4. **Generic Storage**: Uses existing `general_service_requests` table structure
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Schema Changes
|
|
15
|
+
|
|
16
|
+
### 1. Update `ServiceRequestsModel` (general_service_requests)
|
|
17
|
+
|
|
18
|
+
**Add new columns:**
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
@Column({ type: 'int', nullable: true })
|
|
22
|
+
issue_type_id: number | null; // Reference to issue types table
|
|
23
|
+
|
|
24
|
+
@Column({ type: 'varchar', length: 255, nullable: true })
|
|
25
|
+
issue_type_name: string | null; // Denormalized for quick access
|
|
26
|
+
|
|
27
|
+
@Column({ type: 'varchar', length: 255, nullable: true })
|
|
28
|
+
group_name: string | null; // Auto-populated routing group
|
|
29
|
+
|
|
30
|
+
@Column({ type: 'int', nullable: true })
|
|
31
|
+
assigned_group_id: number | null; // Reference to routing groups table (optional)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Rationale:**
|
|
35
|
+
- `issue_type_id`: Links to issue types configuration
|
|
36
|
+
- `issue_type_name`: Denormalized for performance (no join needed for listing)
|
|
37
|
+
- `group_name`: Auto-populated based on routing rules
|
|
38
|
+
- `assigned_group_id`: Optional reference if you want a groups table
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
### 2. Create `IssueTypes` Model (NEW)
|
|
43
|
+
|
|
44
|
+
**Purpose**: Master data for issue types
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
@Entity({ name: 'issue_types' })
|
|
48
|
+
export class IssueTypes extends BaseModel {
|
|
49
|
+
@Column({ type: 'varchar', length: 100 })
|
|
50
|
+
name: string; // e.g., "Hardware Issue", "Software Issue", "Network Problem"
|
|
51
|
+
|
|
52
|
+
@Column({ type: 'varchar', length: 500, nullable: true })
|
|
53
|
+
description: string | null;
|
|
54
|
+
|
|
55
|
+
@Column({ type: 'int' })
|
|
56
|
+
service_id: number; // Category
|
|
57
|
+
|
|
58
|
+
@Column({ type: 'int' })
|
|
59
|
+
sub_service_id: number; // Subcategory
|
|
60
|
+
|
|
61
|
+
@Column({ type: 'boolean', default: true })
|
|
62
|
+
is_active: boolean;
|
|
63
|
+
|
|
64
|
+
@Column({ type: 'int', nullable: true })
|
|
65
|
+
priority: number | null; // 1=High, 2=Medium, 3=Low
|
|
66
|
+
|
|
67
|
+
constructor(
|
|
68
|
+
name: string,
|
|
69
|
+
service_id: number,
|
|
70
|
+
sub_service_id: number,
|
|
71
|
+
description?: string
|
|
72
|
+
) {
|
|
73
|
+
super();
|
|
74
|
+
this.name = name;
|
|
75
|
+
this.service_id = service_id;
|
|
76
|
+
this.sub_service_id = sub_service_id;
|
|
77
|
+
this.description = description || null;
|
|
78
|
+
this.is_active = true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### 3. Create `RoutingGroups` Model (NEW)
|
|
86
|
+
|
|
87
|
+
**Purpose**: Define routing groups and their assignments
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
@Entity({ name: 'routing_groups' })
|
|
91
|
+
export class RoutingGroups extends BaseModel {
|
|
92
|
+
@Column({ type: 'varchar', length: 255 })
|
|
93
|
+
group_name: string; // e.g., "IT-Hardware-Support", "HR-Payroll-Team"
|
|
94
|
+
|
|
95
|
+
@Column({ type: 'varchar', length: 500, nullable: true })
|
|
96
|
+
description: string | null;
|
|
97
|
+
|
|
98
|
+
@Column({ type: 'int' })
|
|
99
|
+
service_id: number;
|
|
100
|
+
|
|
101
|
+
@Column({ type: 'int' })
|
|
102
|
+
sub_service_id: number;
|
|
103
|
+
|
|
104
|
+
@Column({ type: 'int', nullable: true })
|
|
105
|
+
issue_type_id: number | null; // If null, applies to all issue types in sub-service
|
|
106
|
+
|
|
107
|
+
@Column({ type: 'int', nullable: true })
|
|
108
|
+
default_role_id: number | null; // Primary role for this group (e.g., HOD, HOS)
|
|
109
|
+
|
|
110
|
+
@Column({ type: 'int', nullable: true })
|
|
111
|
+
department_id: number | null; // If specific to department
|
|
112
|
+
|
|
113
|
+
@Column({ type: 'int', nullable: true })
|
|
114
|
+
section_id: number | null; // If specific to section
|
|
115
|
+
|
|
116
|
+
@Column({ type: 'jsonb', nullable: true })
|
|
117
|
+
assigned_role_ids: number[] | null; // Array of role IDs that can handle this group
|
|
118
|
+
|
|
119
|
+
@Column({ type: 'boolean', default: true })
|
|
120
|
+
is_active: boolean;
|
|
121
|
+
|
|
122
|
+
constructor(
|
|
123
|
+
group_name: string,
|
|
124
|
+
service_id: number,
|
|
125
|
+
sub_service_id: number,
|
|
126
|
+
issue_type_id?: number | null
|
|
127
|
+
) {
|
|
128
|
+
super();
|
|
129
|
+
this.group_name = group_name;
|
|
130
|
+
this.service_id = service_id;
|
|
131
|
+
this.sub_service_id = sub_service_id;
|
|
132
|
+
this.issue_type_id = issue_type_id || null;
|
|
133
|
+
this.is_active = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### 4. Create `RoutingRules` Model (NEW - Alternative Approach)
|
|
141
|
+
|
|
142
|
+
**Purpose**: More flexible routing configuration
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
@Entity({ name: 'routing_rules' })
|
|
146
|
+
export class RoutingRules extends BaseModel {
|
|
147
|
+
@Column({ type: 'int' })
|
|
148
|
+
service_id: number;
|
|
149
|
+
|
|
150
|
+
@Column({ type: 'int' })
|
|
151
|
+
sub_service_id: number;
|
|
152
|
+
|
|
153
|
+
@Column({ type: 'int', nullable: true })
|
|
154
|
+
issue_type_id: number | null; // null = applies to all issue types
|
|
155
|
+
|
|
156
|
+
@Column({ type: 'varchar', length: 255 })
|
|
157
|
+
group_name: string; // Auto-populated group name
|
|
158
|
+
|
|
159
|
+
@Column({ type: 'int', nullable: true })
|
|
160
|
+
workflow_definition_id: number | null; // Link to workflow
|
|
161
|
+
|
|
162
|
+
@Column({ type: 'int', nullable: true })
|
|
163
|
+
priority: number | null; // Rule priority (lower = higher priority)
|
|
164
|
+
|
|
165
|
+
@Column({ type: 'jsonb', nullable: true })
|
|
166
|
+
conditions: any | null; // Additional conditions (e.g., department, section)
|
|
167
|
+
|
|
168
|
+
@Column({ type: 'boolean', default: true })
|
|
169
|
+
is_active: boolean;
|
|
170
|
+
|
|
171
|
+
constructor(
|
|
172
|
+
service_id: number,
|
|
173
|
+
sub_service_id: number,
|
|
174
|
+
group_name: string,
|
|
175
|
+
issue_type_id?: number | null
|
|
176
|
+
) {
|
|
177
|
+
super();
|
|
178
|
+
this.service_id = service_id;
|
|
179
|
+
this.sub_service_id = sub_service_id;
|
|
180
|
+
this.group_name = group_name;
|
|
181
|
+
this.issue_type_id = issue_type_id || null;
|
|
182
|
+
this.is_active = true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Auto-Population Logic
|
|
190
|
+
|
|
191
|
+
### When Creating a Request:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
async createHelpdeskRequest(requestData: any) {
|
|
195
|
+
const { service_id, sub_service_id, issue_type_id, user } = requestData;
|
|
196
|
+
|
|
197
|
+
// Step 1: Find routing rule
|
|
198
|
+
const routingRule = await RoutingRulesRepository.findOne({
|
|
199
|
+
where: {
|
|
200
|
+
service_id,
|
|
201
|
+
sub_service_id,
|
|
202
|
+
issue_type_id: issue_type_id || null, // Try specific first
|
|
203
|
+
is_active: true
|
|
204
|
+
},
|
|
205
|
+
order: { priority: 'ASC' }
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Step 2: If no specific rule, try generic (issue_type_id = null)
|
|
209
|
+
if (!routingRule) {
|
|
210
|
+
const genericRule = await RoutingRulesRepository.findOne({
|
|
211
|
+
where: {
|
|
212
|
+
service_id,
|
|
213
|
+
sub_service_id,
|
|
214
|
+
issue_type_id: null,
|
|
215
|
+
is_active: true
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
if (genericRule) {
|
|
220
|
+
routingRule = genericRule;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Step 3: Auto-populate group_name
|
|
225
|
+
const groupName = routingRule?.group_name ||
|
|
226
|
+
`GROUP-${service_id}-${sub_service_id}-${issue_type_id || 'ALL'}`;
|
|
227
|
+
|
|
228
|
+
// Step 4: Create request with group_name
|
|
229
|
+
const serviceRequest = new GeneralServiceRequests(
|
|
230
|
+
user.id,
|
|
231
|
+
user.employee_id,
|
|
232
|
+
user.employee_name,
|
|
233
|
+
user.email_address,
|
|
234
|
+
user.contact_number,
|
|
235
|
+
service_id,
|
|
236
|
+
sub_service_id,
|
|
237
|
+
user.section_id,
|
|
238
|
+
user.reporting_manager
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
serviceRequest.issue_type_id = issue_type_id;
|
|
242
|
+
serviceRequest.issue_type_name = issueType?.name || null;
|
|
243
|
+
serviceRequest.group_name = groupName;
|
|
244
|
+
serviceRequest.assigned_group_id = routingRule?.id || null;
|
|
245
|
+
|
|
246
|
+
return await ServiceRequestsRepository.save(serviceRequest);
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Query Patterns for Role-Based Access
|
|
253
|
+
|
|
254
|
+
### 1. Get My Requests (Requester View)
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
async getMyHelpdeskRequests(userId: number) {
|
|
258
|
+
return await ServiceRequestsRepository.find({
|
|
259
|
+
where: {
|
|
260
|
+
user_id: userId,
|
|
261
|
+
is_deleted: false
|
|
262
|
+
},
|
|
263
|
+
order: { created_at: 'DESC' },
|
|
264
|
+
relations: ['approvals', 'workflows', 'attachments']
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### 2. Get Requests for My Approval (Role-Based)
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
async getRequestsForMyApproval(userId: number, roleIds: number[]) {
|
|
273
|
+
// Get user's department and section
|
|
274
|
+
const user = await UserRepository.findOne({ where: { id: userId } });
|
|
275
|
+
|
|
276
|
+
return await ServiceRequestsRepository
|
|
277
|
+
.createQueryBuilder('sr')
|
|
278
|
+
.innerJoin('general_service_approvals', 'sa', 'sa.service_request_id = sr.id')
|
|
279
|
+
.where('sa.approval_status = :status', { status: 'Pending' })
|
|
280
|
+
.andWhere('sa.approver_role_id IN (:...roleIds)', { roleIds })
|
|
281
|
+
.andWhere('sr.is_deleted = :isDeleted', { isDeleted: false })
|
|
282
|
+
.andWhere('sa.is_deleted = :isDeleted', { isDeleted: false })
|
|
283
|
+
// Optional: Filter by group if user belongs to specific groups
|
|
284
|
+
.andWhere(
|
|
285
|
+
'(sa.department_id = :deptId OR sa.department_id IS NULL)',
|
|
286
|
+
{ deptId: user.department_id }
|
|
287
|
+
)
|
|
288
|
+
.andWhere(
|
|
289
|
+
'(sa.section_id = :sectionId OR sa.section_id IS NULL)',
|
|
290
|
+
{ sectionId: user.section_id }
|
|
291
|
+
)
|
|
292
|
+
.orderBy('sr.created_at', 'DESC')
|
|
293
|
+
.getMany();
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 3. Get Requests by Group (Group Admin View)
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
async getRequestsByGroup(groupName: string, userId: number) {
|
|
301
|
+
// Check if user has access to this group
|
|
302
|
+
const userRoles = await getUserRoles(userId);
|
|
303
|
+
const routingGroup = await RoutingGroupsRepository.findOne({
|
|
304
|
+
where: { group_name: groupName, is_active: true }
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
if (!routingGroup) {
|
|
308
|
+
throw new Error('Group not found');
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Check if user has required role
|
|
312
|
+
const hasAccess = routingGroup.assigned_role_ids?.some(roleId =>
|
|
313
|
+
userRoles.includes(roleId)
|
|
314
|
+
) || userRoles.includes(routingGroup.default_role_id);
|
|
315
|
+
|
|
316
|
+
if (!hasAccess) {
|
|
317
|
+
throw new Error('Access denied to this group');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return await ServiceRequestsRepository.find({
|
|
321
|
+
where: {
|
|
322
|
+
group_name: groupName,
|
|
323
|
+
is_deleted: false
|
|
324
|
+
},
|
|
325
|
+
order: { created_at: 'DESC' },
|
|
326
|
+
relations: ['approvals', 'workflows']
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### 4. Get Requests by Category/Subcategory/Issue Type (Admin View)
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
async getRequestsByFilters(filters: {
|
|
335
|
+
service_id?: number;
|
|
336
|
+
sub_service_id?: number;
|
|
337
|
+
issue_type_id?: number;
|
|
338
|
+
group_name?: string;
|
|
339
|
+
status?: string;
|
|
340
|
+
}) {
|
|
341
|
+
const query = ServiceRequestsRepository.createQueryBuilder('sr')
|
|
342
|
+
.where('sr.is_deleted = :isDeleted', { isDeleted: false });
|
|
343
|
+
|
|
344
|
+
if (filters.service_id) {
|
|
345
|
+
query.andWhere('sr.service_id = :serviceId', { serviceId: filters.service_id });
|
|
346
|
+
}
|
|
347
|
+
if (filters.sub_service_id) {
|
|
348
|
+
query.andWhere('sr.sub_service_id = :subServiceId', { subServiceId: filters.sub_service_id });
|
|
349
|
+
}
|
|
350
|
+
if (filters.issue_type_id) {
|
|
351
|
+
query.andWhere('sr.issue_type_id = :issueTypeId', { issueTypeId: filters.issue_type_id });
|
|
352
|
+
}
|
|
353
|
+
if (filters.group_name) {
|
|
354
|
+
query.andWhere('sr.group_name = :groupName', { groupName: filters.group_name });
|
|
355
|
+
}
|
|
356
|
+
if (filters.status) {
|
|
357
|
+
query.andWhere('sr.request_status = :status', { status: filters.status });
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return await query
|
|
361
|
+
.orderBy('sr.created_at', 'DESC')
|
|
362
|
+
.getMany();
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Workflow Integration
|
|
369
|
+
|
|
370
|
+
The existing workflow system already supports routing based on `service_id` and `sub_service_id`. You can extend it to also consider `issue_type_id`:
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
async getWorkflowHierarchy(serviceId: number, subServiceId: number, issueTypeId?: number) {
|
|
374
|
+
// Option 1: Use existing workflow (service + sub_service)
|
|
375
|
+
let workflowDefinition = await WorkflowDefinitionsRepository.findOne({
|
|
376
|
+
where: {
|
|
377
|
+
service_id: serviceId,
|
|
378
|
+
sub_service_id: subServiceId,
|
|
379
|
+
is_active: true,
|
|
380
|
+
status: 'published'
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// Option 2: If issue_type specific workflow exists, use that
|
|
385
|
+
if (issueTypeId) {
|
|
386
|
+
// You could add issue_type_id to WorkflowDefinitions if needed
|
|
387
|
+
// Or use routing_rules to map to specific workflow
|
|
388
|
+
const routingRule = await RoutingRulesRepository.findOne({
|
|
389
|
+
where: {
|
|
390
|
+
service_id: serviceId,
|
|
391
|
+
sub_service_id: subServiceId,
|
|
392
|
+
issue_type_id: issueTypeId,
|
|
393
|
+
is_active: true
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
if (routingRule?.workflow_definition_id) {
|
|
398
|
+
workflowDefinition = await WorkflowDefinitionsRepository.findOne({
|
|
399
|
+
where: { id: routingRule.workflow_definition_id }
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Get hierarchy as usual
|
|
405
|
+
const hierarchy = await WorkflowHierarchyRepository.find({
|
|
406
|
+
where: {
|
|
407
|
+
workflow_definition_id: workflowDefinition.id,
|
|
408
|
+
is_deleted: false
|
|
409
|
+
},
|
|
410
|
+
order: { step_order: 'ASC' }
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
return { workflowDefinition, hierarchy };
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Recommended Approach
|
|
420
|
+
|
|
421
|
+
### **Option A: Simple (Recommended for MVP)**
|
|
422
|
+
- Add `issue_type_id`, `issue_type_name`, `group_name` to `ServiceRequestsModel`
|
|
423
|
+
- Create `IssueTypes` table
|
|
424
|
+
- Create `RoutingRules` table (simpler than RoutingGroups)
|
|
425
|
+
- Auto-populate `group_name` using routing rules lookup
|
|
426
|
+
|
|
427
|
+
### **Option B: Advanced (For Complex Routing)**
|
|
428
|
+
- Everything from Option A
|
|
429
|
+
- Add `RoutingGroups` table for group management
|
|
430
|
+
- Add `assigned_group_id` to requests
|
|
431
|
+
- Support group-based permissions and assignments
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Migration Steps
|
|
436
|
+
|
|
437
|
+
1. **Create new tables**: `issue_types`, `routing_rules` (or `routing_groups`)
|
|
438
|
+
2. **Alter `general_service_requests`**: Add new columns
|
|
439
|
+
3. **Populate master data**: Insert issue types and routing rules
|
|
440
|
+
4. **Update service layer**: Implement auto-population logic
|
|
441
|
+
5. **Update API endpoints**: Add filters for issue_type and group_name
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Example Data Structure
|
|
446
|
+
|
|
447
|
+
### Issue Types
|
|
448
|
+
```
|
|
449
|
+
id | name | service_id | sub_service_id | is_active
|
|
450
|
+
1 | Hardware Issue | 5 | 12 | true
|
|
451
|
+
2 | Software Issue | 5 | 12 | true
|
|
452
|
+
3 | Network Problem | 5 | 13 | true
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Routing Rules
|
|
456
|
+
```
|
|
457
|
+
id | service_id | sub_service_id | issue_type_id | group_name | workflow_def_id
|
|
458
|
+
1 | 5 | 12 | 1 | IT-Hardware-Support | 10
|
|
459
|
+
2 | 5 | 12 | 2 | IT-Software-Support | 11
|
|
460
|
+
3 | 5 | 12 | null | IT-General-Support | 12
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Request Example
|
|
464
|
+
```
|
|
465
|
+
id | user_id | service_id | sub_service_id | issue_type_id | issue_type_name | group_name | request_status
|
|
466
|
+
1 | 100 | 5 | 12 | 1 | Hardware Issue | IT-Hardware-Support | Pending
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Next Steps
|
|
472
|
+
|
|
473
|
+
1. Review and approve this schema design
|
|
474
|
+
2. Create the new models in `shared_models/src/models/`
|
|
475
|
+
3. Update `ServiceRequestsModel` with new columns
|
|
476
|
+
4. Create migration scripts
|
|
477
|
+
5. Implement auto-population logic in service layer
|
|
478
|
+
6. Update API endpoints for filtering
|
|
479
|
+
|
package/dist/data-source.js
CHANGED
|
@@ -88,6 +88,13 @@ const UpdateAttendanceRequestModel_1 = require("./models/UpdateAttendanceRequest
|
|
|
88
88
|
const UpdateAttendanceApprovalModel_1 = require("./models/UpdateAttendanceApprovalModel");
|
|
89
89
|
const UpdateAttendanceChatModel_1 = require("./models/UpdateAttendanceChatModel");
|
|
90
90
|
const UpdateAttendanceWorkflowModel_1 = require("./models/UpdateAttendanceWorkflowModel");
|
|
91
|
+
const IssueTypesModel_1 = require("./models/IssueTypesModel");
|
|
92
|
+
const RoutingGroupsModel_1 = require("./models/RoutingGroupsModel");
|
|
93
|
+
const ServiceRequestsModel_1 = require("./models/ServiceRequestsModel");
|
|
94
|
+
const ServiceApprovalsModel_1 = require("./models/ServiceApprovalsModel");
|
|
95
|
+
const ServiceWorkFlowModel_1 = require("./models/ServiceWorkFlowModel");
|
|
96
|
+
const ServiceAttachmentsModel_1 = require("./models/ServiceAttachmentsModel");
|
|
97
|
+
const ServiceChatsModel_1 = require("./models/ServiceChatsModel");
|
|
91
98
|
exports.AppDataSource = new typeorm_1.DataSource({
|
|
92
99
|
type: 'postgres',
|
|
93
100
|
host: process.env.DB_HOST || 'localhost',
|
|
@@ -180,6 +187,13 @@ exports.AppDataSource = new typeorm_1.DataSource({
|
|
|
180
187
|
UpdateAttendanceRequestModel_1.UpdateAttendanceRequests,
|
|
181
188
|
UpdateAttendanceApprovalModel_1.UpdateAttendanceApprovalDetails,
|
|
182
189
|
UpdateAttendanceChatModel_1.UpdateAttendanceRequestChat,
|
|
183
|
-
UpdateAttendanceWorkflowModel_1.UpdateAttendanceWorkFlow
|
|
190
|
+
UpdateAttendanceWorkflowModel_1.UpdateAttendanceWorkFlow,
|
|
191
|
+
IssueTypesModel_1.IssueTypes,
|
|
192
|
+
RoutingGroupsModel_1.RoutingGroups,
|
|
193
|
+
ServiceRequestsModel_1.GeneralServiceRequests,
|
|
194
|
+
ServiceApprovalsModel_1.GeneralServiceApprovals,
|
|
195
|
+
ServiceWorkFlowModel_1.GeneralServiceWorkFlow,
|
|
196
|
+
ServiceAttachmentsModel_1.GeneralServiceAttachments,
|
|
197
|
+
ServiceChatsModel_1.GeneralServiceChats
|
|
184
198
|
],
|
|
185
199
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -81,3 +81,10 @@ export * from './models/UpdateAttendanceRequestModel';
|
|
|
81
81
|
export * from './models/UpdateAttendanceApprovalModel';
|
|
82
82
|
export * from './models/UpdateAttendanceChatModel';
|
|
83
83
|
export * from './models/UpdateAttendanceWorkflowModel';
|
|
84
|
+
export * from './models/IssueTypesModel';
|
|
85
|
+
export * from './models/RoutingGroupsModel';
|
|
86
|
+
export * from './models/ServiceRequestsModel';
|
|
87
|
+
export * from './models/ServiceApprovalsModel';
|
|
88
|
+
export * from './models/ServiceWorkFlowModel';
|
|
89
|
+
export * from './models/ServiceAttachmentsModel';
|
|
90
|
+
export * from './models/ServiceChatsModel';
|
package/dist/index.js
CHANGED
|
@@ -97,3 +97,10 @@ __exportStar(require("./models/UpdateAttendanceRequestModel"), exports);
|
|
|
97
97
|
__exportStar(require("./models/UpdateAttendanceApprovalModel"), exports);
|
|
98
98
|
__exportStar(require("./models/UpdateAttendanceChatModel"), exports);
|
|
99
99
|
__exportStar(require("./models/UpdateAttendanceWorkflowModel"), exports);
|
|
100
|
+
__exportStar(require("./models/IssueTypesModel"), exports);
|
|
101
|
+
__exportStar(require("./models/RoutingGroupsModel"), exports);
|
|
102
|
+
__exportStar(require("./models/ServiceRequestsModel"), exports);
|
|
103
|
+
__exportStar(require("./models/ServiceApprovalsModel"), exports);
|
|
104
|
+
__exportStar(require("./models/ServiceWorkFlowModel"), exports);
|
|
105
|
+
__exportStar(require("./models/ServiceAttachmentsModel"), exports);
|
|
106
|
+
__exportStar(require("./models/ServiceChatsModel"), exports);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseModel } from './BaseModel';
|
|
2
|
+
import { FMServices } from './FMServices';
|
|
3
|
+
import { FMSubServices } from './FMSubservices';
|
|
4
|
+
export declare class IssueTypes extends BaseModel {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string | null;
|
|
7
|
+
service_id: number;
|
|
8
|
+
service?: FMServices;
|
|
9
|
+
sub_service_id: number;
|
|
10
|
+
sub_service?: FMSubServices;
|
|
11
|
+
is_active: boolean;
|
|
12
|
+
priority: number | null;
|
|
13
|
+
constructor(name: string, service_id: number, sub_service_id: number, description?: string, priority?: number | null);
|
|
14
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.IssueTypes = void 0;
|
|
13
|
+
const typeorm_1 = require("typeorm");
|
|
14
|
+
const BaseModel_1 = require("./BaseModel");
|
|
15
|
+
const FMServices_1 = require("./FMServices");
|
|
16
|
+
const FMSubservices_1 = require("./FMSubservices");
|
|
17
|
+
let IssueTypes = class IssueTypes extends BaseModel_1.BaseModel {
|
|
18
|
+
constructor(name, service_id, sub_service_id, description, priority) {
|
|
19
|
+
super();
|
|
20
|
+
this.name = name;
|
|
21
|
+
this.service_id = service_id;
|
|
22
|
+
this.sub_service_id = sub_service_id;
|
|
23
|
+
this.description = description || null;
|
|
24
|
+
this.is_active = true;
|
|
25
|
+
this.priority = priority || null;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
exports.IssueTypes = IssueTypes;
|
|
29
|
+
__decorate([
|
|
30
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 100 }),
|
|
31
|
+
__metadata("design:type", String)
|
|
32
|
+
], IssueTypes.prototype, "name", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 500, nullable: true }),
|
|
35
|
+
__metadata("design:type", Object)
|
|
36
|
+
], IssueTypes.prototype, "description", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
(0, typeorm_1.Column)({ type: 'int' }),
|
|
39
|
+
__metadata("design:type", Number)
|
|
40
|
+
], IssueTypes.prototype, "service_id", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
(0, typeorm_1.ManyToOne)(() => FMServices_1.FMServices),
|
|
43
|
+
(0, typeorm_1.JoinColumn)({ name: 'service_id' }),
|
|
44
|
+
__metadata("design:type", FMServices_1.FMServices)
|
|
45
|
+
], IssueTypes.prototype, "service", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
(0, typeorm_1.Column)({ type: 'int' }),
|
|
48
|
+
__metadata("design:type", Number)
|
|
49
|
+
], IssueTypes.prototype, "sub_service_id", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, typeorm_1.ManyToOne)(() => FMSubservices_1.FMSubServices),
|
|
52
|
+
(0, typeorm_1.JoinColumn)({ name: 'sub_service_id' }),
|
|
53
|
+
__metadata("design:type", FMSubservices_1.FMSubServices)
|
|
54
|
+
], IssueTypes.prototype, "sub_service", void 0);
|
|
55
|
+
__decorate([
|
|
56
|
+
(0, typeorm_1.Column)({ type: 'boolean', default: true }),
|
|
57
|
+
__metadata("design:type", Boolean)
|
|
58
|
+
], IssueTypes.prototype, "is_active", void 0);
|
|
59
|
+
__decorate([
|
|
60
|
+
(0, typeorm_1.Column)({ type: 'int', nullable: true }),
|
|
61
|
+
__metadata("design:type", Object)
|
|
62
|
+
], IssueTypes.prototype, "priority", void 0);
|
|
63
|
+
exports.IssueTypes = IssueTypes = __decorate([
|
|
64
|
+
(0, typeorm_1.Entity)({ name: 'issue_types' }),
|
|
65
|
+
__metadata("design:paramtypes", [String, Number, Number, String, Object])
|
|
66
|
+
], IssueTypes);
|
|
@@ -2,7 +2,8 @@ import { BaseModel } from './BaseModel';
|
|
|
2
2
|
export declare enum ApprovalStatus {
|
|
3
3
|
PENDING = "Pending",
|
|
4
4
|
APPROVED = "Approved",
|
|
5
|
-
REJECTED = "Rejected"
|
|
5
|
+
REJECTED = "Rejected",
|
|
6
|
+
IN_PROGRESS = "In Progress"
|
|
6
7
|
}
|
|
7
8
|
export declare class LeaveApprovalDetails extends BaseModel {
|
|
8
9
|
leave_request_id: number;
|
|
@@ -17,6 +17,7 @@ var ApprovalStatus;
|
|
|
17
17
|
ApprovalStatus["PENDING"] = "Pending";
|
|
18
18
|
ApprovalStatus["APPROVED"] = "Approved";
|
|
19
19
|
ApprovalStatus["REJECTED"] = "Rejected";
|
|
20
|
+
ApprovalStatus["IN_PROGRESS"] = "In Progress";
|
|
20
21
|
})(ApprovalStatus || (exports.ApprovalStatus = ApprovalStatus = {}));
|
|
21
22
|
//This model is used to store the store the leave apporval details of the user for the leave request
|
|
22
23
|
let LeaveApprovalDetails = class LeaveApprovalDetails extends BaseModel_1.BaseModel {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseModel } from './BaseModel';
|
|
2
|
+
import { FMServices } from './FMServices';
|
|
3
|
+
import { FMSubServices } from './FMSubservices';
|
|
4
|
+
import { IssueTypes } from './IssueTypesModel';
|
|
5
|
+
export declare class RoutingGroups extends BaseModel {
|
|
6
|
+
group_name: string;
|
|
7
|
+
description: string | null;
|
|
8
|
+
service_id: number;
|
|
9
|
+
service?: FMServices;
|
|
10
|
+
sub_service_id: number;
|
|
11
|
+
sub_service?: FMSubServices;
|
|
12
|
+
issue_type_id: number | null;
|
|
13
|
+
issue_type?: IssueTypes;
|
|
14
|
+
assigned_role_id: number | null;
|
|
15
|
+
department_id: number | null;
|
|
16
|
+
section_id: number | null;
|
|
17
|
+
is_active: boolean;
|
|
18
|
+
constructor(group_name: string, service_id: number, sub_service_id: number, issue_type_id?: number | null, assigned_role_id?: number | null, description?: string);
|
|
19
|
+
}
|