@acorex/modules 20.7.4 → 20.7.6
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/document-management/index.d.ts +3 -2
- package/fesm2022/acorex-modules-document-management.mjs +106 -20
- package/fesm2022/acorex-modules-document-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-human-capital-management-leave-request.entity-CITYAroH.mjs → acorex-modules-human-capital-management-leave-request.entity-Dn2LLbuq.mjs} +20 -3
- package/fesm2022/acorex-modules-human-capital-management-leave-request.entity-Dn2LLbuq.mjs.map +1 -0
- package/fesm2022/acorex-modules-human-capital-management.mjs +558 -103
- package/fesm2022/acorex-modules-human-capital-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-product-catalog-product.entity-CBieRmkK.mjs → acorex-modules-product-catalog-product.entity-CuTXUcc1.mjs} +20 -17
- package/fesm2022/acorex-modules-product-catalog-product.entity-CuTXUcc1.mjs.map +1 -0
- package/fesm2022/acorex-modules-product-catalog.mjs +1 -1
- package/fesm2022/{acorex-modules-task-management-task-board.page-CIlxqtgJ.mjs → acorex-modules-task-management-task-board.page-BNwqZ5Eu.mjs} +3 -3
- package/fesm2022/{acorex-modules-task-management-task-board.page-CIlxqtgJ.mjs.map → acorex-modules-task-management-task-board.page-BNwqZ5Eu.mjs.map} +1 -1
- package/fesm2022/acorex-modules-task-management.mjs +9 -3
- package/fesm2022/acorex-modules-task-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-workflow-management-index-vstmaa5b.mjs → acorex-modules-workflow-management-index-BIl8No8o.mjs} +16 -10
- package/fesm2022/acorex-modules-workflow-management-index-BIl8No8o.mjs.map +1 -0
- package/fesm2022/acorex-modules-workflow-management.mjs +36 -4
- package/fesm2022/acorex-modules-workflow-management.mjs.map +1 -1
- package/human-capital-management/index.d.ts +58 -1
- package/package.json +6 -6
- package/workflow-management/index.d.ts +2 -0
- package/fesm2022/acorex-modules-human-capital-management-leave-request.entity-CITYAroH.mjs.map +0 -1
- package/fesm2022/acorex-modules-product-catalog-product.entity-CBieRmkK.mjs.map +0 -1
- package/fesm2022/acorex-modules-workflow-management-index-vstmaa5b.mjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AXTranslationService } from '@acorex/core/translation';
|
|
2
2
|
import { AXPWorkflowTaskProvider, AXP_WORKFLOW_TASK_PROVIDER } from '@acorex/modules/task-management';
|
|
3
3
|
import { AXPSystemStatuses, AXPStatusProvider, systemStatusToDefinition, AXPSystemStatusType, AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER } from '@acorex/platform/common';
|
|
4
|
-
import { AXPEntityService, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
|
4
|
+
import { AXPEntityService, AXPEntityDefinitionRegistryService, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
|
5
5
|
import { AXPCommandExecutor, AXPCommandEventsService, AXPRuntimeModule, provideCommandSetups } from '@acorex/platform/runtime';
|
|
6
6
|
import * as i0 from '@angular/core';
|
|
7
7
|
import { inject, Injectable, DestroyRef, signal, NgModule, Injector } from '@angular/core';
|
|
@@ -194,17 +194,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
194
194
|
}]
|
|
195
195
|
}] });
|
|
196
196
|
|
|
197
|
+
//#region ---- Imports ----
|
|
198
|
+
//#endregion
|
|
199
|
+
/**
|
|
200
|
+
* Leave Request Task Provider
|
|
201
|
+
*
|
|
202
|
+
* Integrates with workflow engine to show leave request tasks from work items.
|
|
203
|
+
* Uses work items created by workflow engine for human-task activities.
|
|
204
|
+
*
|
|
205
|
+
* Architecture:
|
|
206
|
+
* - Queries work items filtered by entityRefType = 'HumanCapitalManagement.LeaveRequest'
|
|
207
|
+
* - Loads related entity data from entityRefId
|
|
208
|
+
* - Maps work item status to task board status
|
|
209
|
+
* - Provides actions based on workflow activity definitions
|
|
210
|
+
*/
|
|
197
211
|
class AXMLeaveRequestTaskProvider extends AXPWorkflowTaskProvider {
|
|
198
212
|
constructor() {
|
|
213
|
+
//#region ---- Services & Dependencies ----
|
|
199
214
|
super(...arguments);
|
|
200
215
|
this.entityService = inject(AXPEntityService);
|
|
216
|
+
this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
|
|
217
|
+
this.workItemData = this.entityService
|
|
218
|
+
.withEntity('WorkflowManagement', 'WorkItem')
|
|
219
|
+
.data();
|
|
201
220
|
this.leaveRequestData = this.entityService
|
|
202
221
|
.withEntity(RootConfig.module.name, RootConfig.entities.leaveRequest.name)
|
|
203
222
|
.data();
|
|
204
223
|
this.commandExecutor = inject(AXPCommandExecutor);
|
|
205
224
|
this.translationService = inject(AXTranslationService);
|
|
206
225
|
this.dialogService = inject(AXPLeaveRequestDialogService);
|
|
226
|
+
//#endregion
|
|
207
227
|
}
|
|
228
|
+
//#endregion
|
|
229
|
+
//#region ---- Provider Metadata ----
|
|
208
230
|
get name() {
|
|
209
231
|
return 'leave-request';
|
|
210
232
|
}
|
|
@@ -214,184 +236,627 @@ class AXMLeaveRequestTaskProvider extends AXPWorkflowTaskProvider {
|
|
|
214
236
|
get icon() {
|
|
215
237
|
return 'fa-light fa-plane-departure';
|
|
216
238
|
}
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region ---- Task Retrieval ----
|
|
241
|
+
/**
|
|
242
|
+
* Get tasks from work items for leave requests.
|
|
243
|
+
*
|
|
244
|
+
* Queries work items filtered by:
|
|
245
|
+
* - entityRefType = 'HumanCapitalManagement.LeaveRequest'
|
|
246
|
+
* - status (Pending, Claimed, InProgress)
|
|
247
|
+
* - assignee/claimant (if filter provided)
|
|
248
|
+
* - date range (if provided)
|
|
249
|
+
*
|
|
250
|
+
* Then loads related entity data and maps to task board format.
|
|
251
|
+
*/
|
|
217
252
|
async getTasks(options) {
|
|
253
|
+
console.log(`[LeaveRequestTaskProvider] 🔍 getTasks called with options:`, {
|
|
254
|
+
skip: options?.skip,
|
|
255
|
+
take: options?.take,
|
|
256
|
+
assigneeIds: options?.assigneeIds,
|
|
257
|
+
range: options?.range,
|
|
258
|
+
types: options?.types,
|
|
259
|
+
});
|
|
260
|
+
// Build filter for work items
|
|
218
261
|
const baseFilter = { logic: 'and', filters: [] };
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
262
|
+
const entityTypeValue = `${RootConfig.module.name}.${RootConfig.entities.leaveRequest.name}`;
|
|
263
|
+
const workflowNameValue = 'create-leave-request';
|
|
264
|
+
console.log(`[LeaveRequestTaskProvider] 📋 Building filters:`, {
|
|
265
|
+
entityType: entityTypeValue,
|
|
266
|
+
workflowName: workflowNameValue,
|
|
223
267
|
});
|
|
224
|
-
// Filter
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
268
|
+
// Filter by entity type OR workflow instance definitionId
|
|
269
|
+
// Primary: entityRefType (set after entity creation)
|
|
270
|
+
// Fallback: instanceId from workflow instances with definitionId = 'create-leave-request'
|
|
271
|
+
// We'll use OR logic to catch both cases
|
|
272
|
+
const entityTypeFilter = {
|
|
273
|
+
field: 'entityRefType',
|
|
274
|
+
operator: { type: 'equal' },
|
|
275
|
+
value: entityTypeValue,
|
|
276
|
+
};
|
|
277
|
+
// Try to get workflow instance IDs for fallback
|
|
278
|
+
let workflowInstanceIds = [];
|
|
279
|
+
try {
|
|
280
|
+
const workflowInstanceData = this.entityService
|
|
281
|
+
.withEntity('WorkflowManagement', 'WorkflowInstance')
|
|
282
|
+
.data();
|
|
283
|
+
const instances = await workflowInstanceData.query({
|
|
284
|
+
skip: 0,
|
|
285
|
+
take: 100,
|
|
286
|
+
filter: {
|
|
287
|
+
logic: 'and',
|
|
288
|
+
filters: [
|
|
289
|
+
{
|
|
290
|
+
field: 'definitionId',
|
|
291
|
+
operator: { type: 'equal' },
|
|
292
|
+
value: workflowNameValue,
|
|
293
|
+
},
|
|
294
|
+
],
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
workflowInstanceIds = instances.items.map((inst) => inst.id);
|
|
298
|
+
console.log(`[LeaveRequestTaskProvider] 🔍 Found ${workflowInstanceIds.length} workflow instances for '${workflowNameValue}'`);
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
console.warn(`[LeaveRequestTaskProvider] ⚠️ Failed to query workflow instances:`, error);
|
|
302
|
+
}
|
|
303
|
+
// Build OR filter: entityRefType OR instanceId in workflowInstanceIds
|
|
304
|
+
if (workflowInstanceIds.length > 0) {
|
|
305
|
+
baseFilter.filters?.push({
|
|
306
|
+
logic: 'or',
|
|
307
|
+
filters: [
|
|
308
|
+
entityTypeFilter,
|
|
309
|
+
{
|
|
310
|
+
field: 'instanceId',
|
|
311
|
+
operator: { type: 'in' },
|
|
312
|
+
value: workflowInstanceIds,
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
});
|
|
228
316
|
}
|
|
229
|
-
|
|
230
|
-
|
|
317
|
+
else {
|
|
318
|
+
// Only use entityRefType if no workflow instances found
|
|
319
|
+
baseFilter.filters?.push(entityTypeFilter);
|
|
231
320
|
}
|
|
321
|
+
// Filter by status (exclude completed/cancelled)
|
|
322
|
+
baseFilter.filters?.push({
|
|
323
|
+
field: 'status',
|
|
324
|
+
operator: { type: 'in' },
|
|
325
|
+
value: ['Pending', 'Claimed', 'InProgress'],
|
|
326
|
+
});
|
|
327
|
+
// Filter by date range if provided
|
|
328
|
+
// Work items don't have startDate/endDate directly, but we can filter by createdAt or dueDate
|
|
329
|
+
// For now, we'll skip date range filtering to ensure work items are found
|
|
330
|
+
// TODO: Implement proper date range filtering based on entity data (startDate/endDate)
|
|
331
|
+
// if (options?.range?.from || options?.range?.end) {
|
|
332
|
+
// if (options.range.from) {
|
|
333
|
+
// baseFilter.filters?.push({
|
|
334
|
+
// field: 'createdAt',
|
|
335
|
+
// operator: { type: 'gte' as const },
|
|
336
|
+
// value: options.range.from,
|
|
337
|
+
// });
|
|
338
|
+
// }
|
|
339
|
+
//
|
|
340
|
+
// if (options.range.end) {
|
|
341
|
+
// // For end date, we want: dueDate <= end OR dueDate is null
|
|
342
|
+
// // This allows work items without dueDate to still appear
|
|
343
|
+
// baseFilter.filters?.push({
|
|
344
|
+
// logic: 'or',
|
|
345
|
+
// filters: [
|
|
346
|
+
// {
|
|
347
|
+
// field: 'dueDate',
|
|
348
|
+
// operator: { type: 'lte' as const },
|
|
349
|
+
// value: options.range.end,
|
|
350
|
+
// },
|
|
351
|
+
// {
|
|
352
|
+
// field: 'dueDate',
|
|
353
|
+
// operator: { type: 'isNull' as const },
|
|
354
|
+
// },
|
|
355
|
+
// ],
|
|
356
|
+
// });
|
|
357
|
+
// }
|
|
358
|
+
// }
|
|
359
|
+
// Filter by assignee/claimant
|
|
232
360
|
if (options?.assigneeIds && options.assigneeIds.length > 0) {
|
|
233
|
-
// Filter by manager (assignee) of the employee requesting leave
|
|
234
361
|
baseFilter.filters?.push({
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
362
|
+
logic: 'or',
|
|
363
|
+
filters: [
|
|
364
|
+
{
|
|
365
|
+
field: 'assignedUserId',
|
|
366
|
+
operator: { type: 'in' },
|
|
367
|
+
value: options.assigneeIds,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
field: 'claimedByUserId',
|
|
371
|
+
operator: { type: 'in' },
|
|
372
|
+
value: options.assigneeIds,
|
|
373
|
+
},
|
|
374
|
+
],
|
|
238
375
|
});
|
|
239
376
|
}
|
|
240
|
-
|
|
377
|
+
console.log(`[LeaveRequestTaskProvider] 🔎 Query filter:`, JSON.stringify(baseFilter, null, 2));
|
|
378
|
+
// Query work items
|
|
379
|
+
const { items: workItems, total } = await this.workItemData.query({
|
|
241
380
|
skip: options?.skip ?? 0,
|
|
242
381
|
take: options?.take ?? 20,
|
|
243
382
|
filter: baseFilter,
|
|
244
383
|
});
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
index: 2,
|
|
263
|
-
status: { id: statusId, title: statusTitle },
|
|
264
|
-
priority: this.getPriorityFromStatus(statusId),
|
|
265
|
-
reporter: {
|
|
266
|
-
id: item.employee?.userId ?? item.employeeId,
|
|
267
|
-
type: 'user',
|
|
268
|
-
fullName: item.employee?.person?.displayName ?? '',
|
|
269
|
-
},
|
|
270
|
-
payload: item,
|
|
271
|
-
};
|
|
384
|
+
console.log(`[LeaveRequestTaskProvider] 📦 Query result:`, {
|
|
385
|
+
total,
|
|
386
|
+
itemsCount: workItems.length,
|
|
387
|
+
workItems: workItems.map((wi) => ({
|
|
388
|
+
id: wi.id,
|
|
389
|
+
title: wi.title,
|
|
390
|
+
status: wi.status,
|
|
391
|
+
entityRefType: wi.entityRefType,
|
|
392
|
+
entityRefId: wi.entityRefId,
|
|
393
|
+
instanceId: wi.instanceId,
|
|
394
|
+
instanceDefinitionId: wi.instance?.definitionId,
|
|
395
|
+
instanceName: wi.instance?.name,
|
|
396
|
+
activityNodeId: wi.activityNodeId,
|
|
397
|
+
activityName: wi.activityName,
|
|
398
|
+
createdAt: wi.createdAt,
|
|
399
|
+
dueDate: wi.dueDate,
|
|
400
|
+
})),
|
|
272
401
|
});
|
|
402
|
+
// Debug: Log if no work items found
|
|
403
|
+
if (workItems.length === 0) {
|
|
404
|
+
console.warn(`[LeaveRequestTaskProvider] ⚠️ No work items found!`, {
|
|
405
|
+
filter: baseFilter,
|
|
406
|
+
entityTypeValue: `${RootConfig.module.name}.${RootConfig.entities.leaveRequest.name}`,
|
|
407
|
+
workflowNameValue: 'create-leave-request',
|
|
408
|
+
suggestion: 'Check if: 1) Workflow was started, 2) Human-task activity exists, 3) Work item was created, 4) entityRefType was set after entity creation',
|
|
409
|
+
});
|
|
410
|
+
// Fallback: Try to query all work items to see what we have
|
|
411
|
+
const allWorkItems = await this.workItemData.query({
|
|
412
|
+
skip: 0,
|
|
413
|
+
take: 10,
|
|
414
|
+
filter: {
|
|
415
|
+
logic: 'and',
|
|
416
|
+
filters: [
|
|
417
|
+
{
|
|
418
|
+
field: 'status',
|
|
419
|
+
operator: { type: 'in' },
|
|
420
|
+
value: ['Pending', 'Claimed', 'InProgress'],
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
console.log(`[LeaveRequestTaskProvider] 🔍 Fallback: Found ${allWorkItems.items.length} work items total (any entity):`, {
|
|
426
|
+
workItems: allWorkItems.items.map((wi) => ({
|
|
427
|
+
id: wi.id,
|
|
428
|
+
title: wi.title,
|
|
429
|
+
entityRefType: wi.entityRefType,
|
|
430
|
+
entityRefId: wi.entityRefId,
|
|
431
|
+
instanceId: wi.instanceId,
|
|
432
|
+
status: wi.status,
|
|
433
|
+
})),
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
// Load entity data for each work item and map to tasks
|
|
437
|
+
const tasks = [];
|
|
438
|
+
console.log(`[LeaveRequestTaskProvider] 🔄 Processing ${workItems.length} work items...`);
|
|
439
|
+
for (const workItem of workItems) {
|
|
440
|
+
try {
|
|
441
|
+
console.log(`[LeaveRequestTaskProvider] 📝 Processing work item:`, {
|
|
442
|
+
id: workItem.id,
|
|
443
|
+
title: workItem.title,
|
|
444
|
+
entityRefId: workItem.entityRefId,
|
|
445
|
+
entityRefType: workItem.entityRefType,
|
|
446
|
+
instanceId: workItem.instanceId,
|
|
447
|
+
instanceDefinitionId: workItem.instance?.definitionId,
|
|
448
|
+
});
|
|
449
|
+
// Load entity data if entityRefId is available
|
|
450
|
+
let entityData = null;
|
|
451
|
+
if (workItem.entityRefId) {
|
|
452
|
+
try {
|
|
453
|
+
console.log(`[LeaveRequestTaskProvider] 🔍 Loading entity data for entityRefId: ${workItem.entityRefId}`);
|
|
454
|
+
entityData = await this.leaveRequestData.byKey(workItem.entityRefId);
|
|
455
|
+
console.log(`[LeaveRequestTaskProvider] ✅ Entity data loaded:`, {
|
|
456
|
+
id: entityData?.id,
|
|
457
|
+
employee: entityData?.employee?.person?.displayName,
|
|
458
|
+
startDate: entityData?.startDate,
|
|
459
|
+
endDate: entityData?.endDate,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
console.warn(`[LeaveRequestTaskProvider] ⚠️ Failed to load entity data for ${workItem.entityRefId}:`, error);
|
|
464
|
+
// Continue without entity data - use work item data only
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
console.log(`[LeaveRequestTaskProvider] ℹ️ No entityRefId, using work item data only`);
|
|
469
|
+
}
|
|
470
|
+
// Map work item to task
|
|
471
|
+
const task = this.mapWorkItemToTask(workItem, entityData);
|
|
472
|
+
console.log(`[LeaveRequestTaskProvider] ✅ Mapped to task:`, {
|
|
473
|
+
id: task.id,
|
|
474
|
+
title: task.title,
|
|
475
|
+
startDate: task.startDate,
|
|
476
|
+
endDate: task.endDate,
|
|
477
|
+
status: task.status,
|
|
478
|
+
});
|
|
479
|
+
tasks.push(task);
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
console.error(`[LeaveRequestTaskProvider] ❌ Failed to process work item ${workItem.id}:`, error);
|
|
483
|
+
// Skip this work item and continue
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
console.log(`[LeaveRequestTaskProvider] ✅ Returning ${tasks.length} tasks (total: ${total})`);
|
|
273
487
|
return { items: tasks, total };
|
|
274
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* Map work item to task board task format.
|
|
491
|
+
*/
|
|
492
|
+
mapWorkItemToTask(workItem, entityData) {
|
|
493
|
+
// Use entity data if available, otherwise use work item metadata
|
|
494
|
+
const statusId = entityData?.statusId ?? entityData?.status?.id ?? AXPSystemStatuses.Pending.name;
|
|
495
|
+
const statusTitle = entityData?.status?.title ??
|
|
496
|
+
this.translationService.translateSync(`@human-capital-management:leave-requests.states.${statusId}`);
|
|
497
|
+
// Extract dates from entity data or use work item dates
|
|
498
|
+
const startDate = entityData?.startDate
|
|
499
|
+
? new Date(entityData.startDate)
|
|
500
|
+
: (workItem.dueDate ? new Date(workItem.dueDate) : new Date());
|
|
501
|
+
const endDate = entityData?.endDate
|
|
502
|
+
? new Date(entityData.endDate)
|
|
503
|
+
: (workItem.dueDate ? new Date(workItem.dueDate) : new Date());
|
|
504
|
+
// Build title from entity data or work item
|
|
505
|
+
let title = workItem.title;
|
|
506
|
+
if (entityData) {
|
|
507
|
+
title = `${entityData.employee?.person?.displayName ?? ''} - ${this.translationService.translateSync(entityData.leaveType?.title ?? '')}`.trim();
|
|
508
|
+
if (!title)
|
|
509
|
+
title = workItem.title;
|
|
510
|
+
}
|
|
511
|
+
// Map work item status to task status
|
|
512
|
+
const taskStatus = this.mapWorkItemStatusToTaskStatus(workItem.status);
|
|
513
|
+
return {
|
|
514
|
+
id: workItem.id, // Use work item ID as task ID
|
|
515
|
+
title,
|
|
516
|
+
description: entityData?.reason ?? workItem.description ?? '',
|
|
517
|
+
startDate,
|
|
518
|
+
endDate,
|
|
519
|
+
allDay: true, // Leave requests are all-day events
|
|
520
|
+
assignee: workItem.assignedUser
|
|
521
|
+
? {
|
|
522
|
+
id: workItem.assignedUser.id,
|
|
523
|
+
type: 'user',
|
|
524
|
+
fullName: workItem.assignedUser.displayName,
|
|
525
|
+
}
|
|
526
|
+
: workItem.claimedByUser
|
|
527
|
+
? {
|
|
528
|
+
id: workItem.claimedByUser.id,
|
|
529
|
+
type: 'user',
|
|
530
|
+
fullName: workItem.claimedByUser.displayName,
|
|
531
|
+
}
|
|
532
|
+
: undefined,
|
|
533
|
+
index: 2,
|
|
534
|
+
status: taskStatus,
|
|
535
|
+
priority: this.mapWorkItemPriorityToTaskPriority(workItem.priority),
|
|
536
|
+
reporter: entityData?.employee
|
|
537
|
+
? {
|
|
538
|
+
id: entityData.employee.userId ?? entityData.employeeId,
|
|
539
|
+
type: 'user',
|
|
540
|
+
fullName: entityData.employee.person?.displayName ?? '',
|
|
541
|
+
}
|
|
542
|
+
: workItem.createdByUser
|
|
543
|
+
? {
|
|
544
|
+
id: workItem.createdByUser.id,
|
|
545
|
+
type: 'user',
|
|
546
|
+
fullName: workItem.createdByUser.displayName,
|
|
547
|
+
}
|
|
548
|
+
: {
|
|
549
|
+
id: '',
|
|
550
|
+
type: 'user',
|
|
551
|
+
fullName: '',
|
|
552
|
+
},
|
|
553
|
+
data: {
|
|
554
|
+
// Store entity data and work item metadata
|
|
555
|
+
entityData: entityData ?? null,
|
|
556
|
+
workItem: workItem,
|
|
557
|
+
workItemId: workItem.id,
|
|
558
|
+
instanceId: workItem.instanceId,
|
|
559
|
+
activityNodeId: workItem.activityNodeId,
|
|
560
|
+
entityRefId: workItem.entityRefId,
|
|
561
|
+
entityRefType: workItem.entityRefType,
|
|
562
|
+
}, // Additional metadata for task processing
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Map work item status to task board status.
|
|
567
|
+
*/
|
|
568
|
+
mapWorkItemStatusToTaskStatus(workItemStatus) {
|
|
569
|
+
// Map work item status to entity status
|
|
570
|
+
switch (workItemStatus) {
|
|
571
|
+
case 'Pending':
|
|
572
|
+
return {
|
|
573
|
+
id: AXPSystemStatuses.Pending.name,
|
|
574
|
+
title: this.translationService.translateSync('@human-capital-management:leave-requests.states.pending'),
|
|
575
|
+
};
|
|
576
|
+
case 'Claimed':
|
|
577
|
+
case 'InProgress':
|
|
578
|
+
return {
|
|
579
|
+
id: AXPSystemStatuses.Pending.name, // Still pending from entity perspective
|
|
580
|
+
title: this.translationService.translateSync('@human-capital-management:leave-requests.states.pending'),
|
|
581
|
+
};
|
|
582
|
+
case 'Completed':
|
|
583
|
+
return {
|
|
584
|
+
id: AXPSystemStatuses.Approved.name, // Completed work item = approved
|
|
585
|
+
title: this.translationService.translateSync('@human-capital-management:leave-requests.states.approved'),
|
|
586
|
+
};
|
|
587
|
+
case 'Rejected':
|
|
588
|
+
return {
|
|
589
|
+
id: AXPSystemStatuses.Rejected.name,
|
|
590
|
+
title: this.translationService.translateSync('@human-capital-management:leave-requests.states.rejected'),
|
|
591
|
+
};
|
|
592
|
+
case 'Cancelled':
|
|
593
|
+
return {
|
|
594
|
+
id: AXPSystemStatuses.Cancelled.name,
|
|
595
|
+
title: this.translationService.translateSync('@human-capital-management:leave-requests.states.cancelled'),
|
|
596
|
+
};
|
|
597
|
+
default:
|
|
598
|
+
return {
|
|
599
|
+
id: AXPSystemStatuses.Pending.name,
|
|
600
|
+
title: this.translationService.translateSync('@human-capital-management:leave-requests.states.pending'),
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Map work item priority to task board priority.
|
|
606
|
+
*/
|
|
607
|
+
mapWorkItemPriorityToTaskPriority(workItemPriority) {
|
|
608
|
+
switch (workItemPriority) {
|
|
609
|
+
case 'Urgent':
|
|
610
|
+
return 'highest';
|
|
611
|
+
case 'High':
|
|
612
|
+
return 'high';
|
|
613
|
+
case 'Normal':
|
|
614
|
+
return 'medium';
|
|
615
|
+
case 'Low':
|
|
616
|
+
return 'low';
|
|
617
|
+
default:
|
|
618
|
+
return 'medium';
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
//#endregion
|
|
622
|
+
//#region ---- Task Updates ----
|
|
623
|
+
/**
|
|
624
|
+
* Update tasks (work items and/or entity data).
|
|
625
|
+
*
|
|
626
|
+
* Updates both work item (if task ID is work item ID) and entity data (if entityRefId is available).
|
|
627
|
+
*/
|
|
275
628
|
async updateTasks(tasksToUpdate) {
|
|
276
|
-
// Update each task in the backend
|
|
277
629
|
const updatedTasks = [];
|
|
278
630
|
for (const task of tasksToUpdate) {
|
|
279
631
|
try {
|
|
280
|
-
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
if
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
632
|
+
const taskData = task.data;
|
|
633
|
+
const workItemId = taskData?.workItemId ?? task.id;
|
|
634
|
+
const entityRefId = taskData?.entityRefId;
|
|
635
|
+
// Update work item if task ID is work item ID
|
|
636
|
+
if (workItemId) {
|
|
637
|
+
const workItemUpdate = {};
|
|
638
|
+
if (task.status?.id) {
|
|
639
|
+
// Map task status back to work item status
|
|
640
|
+
const workItemStatus = this.mapTaskStatusToWorkItemStatus(String(task.status.id));
|
|
641
|
+
if (workItemStatus) {
|
|
642
|
+
workItemUpdate['status'] = workItemStatus;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (task.assignee?.id) {
|
|
646
|
+
workItemUpdate['assignedUserId'] = task.assignee.id;
|
|
647
|
+
}
|
|
648
|
+
if (Object.keys(workItemUpdate).length > 0) {
|
|
649
|
+
await this.workItemData.update(workItemId, workItemUpdate);
|
|
650
|
+
}
|
|
290
651
|
}
|
|
291
|
-
if
|
|
292
|
-
|
|
652
|
+
// Update entity data if entityRefId is available
|
|
653
|
+
if (entityRefId) {
|
|
654
|
+
const entityUpdate = {};
|
|
655
|
+
if (task.status?.id) {
|
|
656
|
+
const statusId = task.status.id;
|
|
657
|
+
entityUpdate['statusId'] = statusId;
|
|
658
|
+
}
|
|
659
|
+
if (task.startDate) {
|
|
660
|
+
entityUpdate['startDate'] = task.startDate;
|
|
661
|
+
}
|
|
662
|
+
if (task.endDate) {
|
|
663
|
+
entityUpdate['endDate'] = task.endDate;
|
|
664
|
+
}
|
|
665
|
+
if (Object.keys(entityUpdate).length > 0) {
|
|
666
|
+
await this.leaveRequestData.update(entityRefId, entityUpdate);
|
|
667
|
+
}
|
|
293
668
|
}
|
|
294
|
-
// Only update if there's something to update
|
|
295
|
-
if (Object.keys(updatePayload).length > 0) {
|
|
296
|
-
await this.leaveRequestData.update(String(task.id), updatePayload);
|
|
297
|
-
}
|
|
298
|
-
// Return the task as-is (already updated in the task object)
|
|
299
669
|
updatedTasks.push(task);
|
|
300
670
|
}
|
|
301
671
|
catch (error) {
|
|
302
672
|
console.error(`[LeaveRequestTaskProvider] Failed to update task ${task.id}:`, error);
|
|
303
|
-
// Still include the task even if update failed
|
|
304
|
-
updatedTasks.push(task);
|
|
673
|
+
updatedTasks.push(task); // Still include the task even if update failed
|
|
305
674
|
}
|
|
306
675
|
}
|
|
307
676
|
return updatedTasks;
|
|
308
677
|
}
|
|
678
|
+
/**
|
|
679
|
+
* Map task status to work item status.
|
|
680
|
+
*/
|
|
681
|
+
mapTaskStatusToWorkItemStatus(taskStatusId) {
|
|
682
|
+
switch (taskStatusId) {
|
|
683
|
+
case AXPSystemStatuses.Pending.name:
|
|
684
|
+
return 'Pending';
|
|
685
|
+
case AXPSystemStatuses.Approved.name:
|
|
686
|
+
return 'Completed';
|
|
687
|
+
case AXPSystemStatuses.Rejected.name:
|
|
688
|
+
return 'Rejected';
|
|
689
|
+
case AXPSystemStatuses.Cancelled.name:
|
|
690
|
+
return 'Cancelled';
|
|
691
|
+
default:
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
//#endregion
|
|
696
|
+
//#region ---- Command Execution ----
|
|
697
|
+
/**
|
|
698
|
+
* Execute commands on tasks.
|
|
699
|
+
*
|
|
700
|
+
* Supports:
|
|
701
|
+
* - Workflow work item commands (Claim, Complete, Cancel)
|
|
702
|
+
* - Leave request business commands (Approve, Reject, Cancel)
|
|
703
|
+
*/
|
|
309
704
|
async executeCommand(command) {
|
|
310
705
|
if (!command?.name)
|
|
311
706
|
return { success: true };
|
|
312
|
-
const
|
|
707
|
+
const workItemId = command.options?.['workItemId'] ?? command.options?.['id'] ?? '';
|
|
708
|
+
const entityRefId = command.options?.['entityRefId'] ?? '';
|
|
709
|
+
// Handle workflow work item commands
|
|
710
|
+
if (command.name === 'WorkflowManagement.WorkItem:Claim') {
|
|
711
|
+
const result = await this.commandExecutor.execute('WorkflowManagement.WorkItem:Claim', {
|
|
712
|
+
id: workItemId,
|
|
713
|
+
});
|
|
714
|
+
return result ?? { success: true };
|
|
715
|
+
}
|
|
716
|
+
if (command.name === 'WorkflowManagement.WorkItem:Complete') {
|
|
717
|
+
const result = await this.commandExecutor.execute('WorkflowManagement.WorkItem:Complete', {
|
|
718
|
+
id: workItemId,
|
|
719
|
+
output: command.options?.['output'] ?? {},
|
|
720
|
+
outcome: command.options?.['outcome'] ?? 'Done',
|
|
721
|
+
});
|
|
722
|
+
return result ?? { success: true };
|
|
723
|
+
}
|
|
724
|
+
if (command.name === 'WorkflowManagement.WorkItem:Cancel') {
|
|
725
|
+
const result = await this.commandExecutor.execute('WorkflowManagement.WorkItem:Cancel', {
|
|
726
|
+
id: workItemId,
|
|
727
|
+
});
|
|
728
|
+
return result ?? { success: true };
|
|
729
|
+
}
|
|
730
|
+
// Handle leave request business commands (for backward compatibility)
|
|
313
731
|
switch (command.name) {
|
|
314
732
|
case 'approveLeave': {
|
|
315
|
-
// Show approval dialog
|
|
316
733
|
const dialogResult = await this.dialogService.showApprovalDialog();
|
|
317
|
-
// If dialog was cancelled, return early
|
|
318
734
|
if (dialogResult?.cancelled) {
|
|
319
735
|
return { success: false };
|
|
320
736
|
}
|
|
321
|
-
//
|
|
737
|
+
// Try to complete work item if available, otherwise use entity command
|
|
738
|
+
if (workItemId) {
|
|
739
|
+
const result = await this.commandExecutor.execute('WorkflowManagement.WorkItem:Complete', {
|
|
740
|
+
id: workItemId,
|
|
741
|
+
output: { reason: dialogResult?.reason, note: dialogResult?.note },
|
|
742
|
+
outcome: 'Approved',
|
|
743
|
+
});
|
|
744
|
+
return result ?? { success: true };
|
|
745
|
+
}
|
|
746
|
+
// Fallback to entity command
|
|
322
747
|
const result = await this.commandExecutor.execute('HumanCapitalManagement.LeaveRequest:Approve', {
|
|
323
|
-
id:
|
|
748
|
+
id: entityRefId || workItemId,
|
|
324
749
|
reason: dialogResult?.reason,
|
|
325
750
|
note: dialogResult?.note,
|
|
326
751
|
});
|
|
327
|
-
// Return result if exists, otherwise default to success (command might not be registered yet)
|
|
328
752
|
return result ?? { success: true };
|
|
329
753
|
}
|
|
330
754
|
case 'rejectLeave': {
|
|
331
|
-
// Show rejection dialog
|
|
332
755
|
const dialogResult = await this.dialogService.showRejectionDialog();
|
|
333
|
-
// If dialog was cancelled, return early
|
|
334
756
|
if (dialogResult?.cancelled) {
|
|
335
757
|
return { success: false };
|
|
336
758
|
}
|
|
337
|
-
//
|
|
759
|
+
// Try to complete work item if available, otherwise use entity command
|
|
760
|
+
if (workItemId) {
|
|
761
|
+
const result = await this.commandExecutor.execute('WorkflowManagement.WorkItem:Complete', {
|
|
762
|
+
id: workItemId,
|
|
763
|
+
output: { reason: dialogResult?.reason, note: dialogResult?.note },
|
|
764
|
+
outcome: 'Rejected',
|
|
765
|
+
});
|
|
766
|
+
return result ?? { success: true };
|
|
767
|
+
}
|
|
768
|
+
// Fallback to entity command
|
|
338
769
|
const result = await this.commandExecutor.execute('HumanCapitalManagement.LeaveRequest:Reject', {
|
|
339
|
-
id:
|
|
770
|
+
id: entityRefId || workItemId,
|
|
340
771
|
reason: dialogResult?.reason,
|
|
341
772
|
note: dialogResult?.note,
|
|
342
773
|
});
|
|
343
|
-
// Return result if exists, otherwise default to success (command might not be registered yet)
|
|
344
774
|
return result ?? { success: true };
|
|
345
775
|
}
|
|
346
776
|
case 'cancelLeave': {
|
|
347
|
-
// Show cancellation dialog
|
|
348
777
|
const dialogResult = await this.dialogService.showCancellationDialog();
|
|
349
|
-
// If dialog was cancelled, return early
|
|
350
778
|
if (dialogResult?.cancelled) {
|
|
351
779
|
return { success: false };
|
|
352
780
|
}
|
|
353
|
-
//
|
|
781
|
+
// Try to cancel work item if available, otherwise use entity command
|
|
782
|
+
if (workItemId) {
|
|
783
|
+
const result = await this.commandExecutor.execute('WorkflowManagement.WorkItem:Cancel', {
|
|
784
|
+
id: workItemId,
|
|
785
|
+
});
|
|
786
|
+
return result ?? { success: true };
|
|
787
|
+
}
|
|
788
|
+
// Fallback to entity command
|
|
354
789
|
const result = await this.commandExecutor.execute('HumanCapitalManagement.LeaveRequest:Cancel', {
|
|
355
|
-
id:
|
|
790
|
+
id: entityRefId || workItemId,
|
|
356
791
|
reason: dialogResult?.reason,
|
|
357
792
|
note: dialogResult?.note,
|
|
358
793
|
});
|
|
359
|
-
// Return result if exists, otherwise default to success (command might not be registered yet)
|
|
360
794
|
return result ?? { success: true };
|
|
361
795
|
}
|
|
362
796
|
}
|
|
363
797
|
return { success: true };
|
|
364
798
|
}
|
|
799
|
+
//#endregion
|
|
800
|
+
//#region ---- Actions & Statuses ----
|
|
801
|
+
/**
|
|
802
|
+
* Get available actions for a task.
|
|
803
|
+
*
|
|
804
|
+
* Provides actions based on work item status and workflow activity.
|
|
805
|
+
*/
|
|
365
806
|
async getActions(task) {
|
|
366
807
|
const actions = [];
|
|
367
|
-
|
|
368
|
-
|
|
808
|
+
if (!task)
|
|
809
|
+
return actions;
|
|
810
|
+
const taskData = task.data;
|
|
811
|
+
const workItemId = taskData?.workItemId ?? task.id;
|
|
812
|
+
const entityRefId = taskData?.entityRefId;
|
|
813
|
+
// Add workflow work item actions
|
|
814
|
+
if (task.status?.id === AXPSystemStatuses.Pending.name) {
|
|
815
|
+
// Claim action (if not already claimed)
|
|
816
|
+
actions.push({
|
|
817
|
+
name: 'WorkflowManagement.WorkItem:Claim',
|
|
818
|
+
title: this.translationService.translateSync('@workflow-management:work-items.actions.claim.title'),
|
|
819
|
+
icon: 'fa-light fa-hand',
|
|
820
|
+
color: 'primary',
|
|
821
|
+
command: {
|
|
822
|
+
name: 'WorkflowManagement.WorkItem:Claim',
|
|
823
|
+
options: { id: workItemId, workItemId },
|
|
824
|
+
},
|
|
825
|
+
});
|
|
826
|
+
// Complete action (with approve/reject outcomes)
|
|
369
827
|
actions.push({
|
|
370
828
|
name: 'approveLeave',
|
|
371
829
|
title: this.translationService.translateSync('@general:actions.approve.title'),
|
|
372
830
|
icon: 'fa-light fa-check',
|
|
373
831
|
color: 'success',
|
|
374
|
-
command: {
|
|
832
|
+
command: {
|
|
833
|
+
name: 'approveLeave',
|
|
834
|
+
options: { id: entityRefId || workItemId, workItemId, entityRefId },
|
|
835
|
+
},
|
|
375
836
|
});
|
|
376
|
-
}
|
|
377
|
-
// Add reject action for pending or approved requests
|
|
378
|
-
if (task?.status?.id === AXPSystemStatuses.Pending.name || task?.status?.id === AXPSystemStatuses.Approved.name) {
|
|
379
837
|
actions.push({
|
|
380
838
|
name: 'rejectLeave',
|
|
381
839
|
title: this.translationService.translateSync('@general:actions.reject.title'),
|
|
382
840
|
icon: 'fa-light fa-xmark',
|
|
383
841
|
color: 'danger',
|
|
384
|
-
command: {
|
|
842
|
+
command: {
|
|
843
|
+
name: 'rejectLeave',
|
|
844
|
+
options: { id: entityRefId || workItemId, workItemId, entityRefId },
|
|
845
|
+
},
|
|
385
846
|
});
|
|
386
847
|
}
|
|
387
|
-
// Add cancel action
|
|
388
|
-
if (task
|
|
848
|
+
// Add cancel action
|
|
849
|
+
if (task.status?.id === AXPSystemStatuses.Pending.name ||
|
|
850
|
+
task.status?.id === AXPSystemStatuses.Approved.name) {
|
|
389
851
|
actions.push({
|
|
390
|
-
name: '
|
|
852
|
+
name: 'cancelLeave',
|
|
391
853
|
title: this.translationService.translateSync('@general:actions.cancel.title'),
|
|
392
854
|
icon: 'fa-light fa-ban',
|
|
393
855
|
color: 'secondary',
|
|
394
|
-
command: {
|
|
856
|
+
command: {
|
|
857
|
+
name: 'cancelLeave',
|
|
858
|
+
options: { id: entityRefId || workItemId, workItemId, entityRefId },
|
|
859
|
+
},
|
|
395
860
|
});
|
|
396
861
|
}
|
|
397
862
|
return actions;
|
|
@@ -427,18 +892,8 @@ class AXMLeaveRequestTaskProvider extends AXPWorkflowTaskProvider {
|
|
|
427
892
|
},
|
|
428
893
|
];
|
|
429
894
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
case AXPSystemStatuses.Pending.name:
|
|
433
|
-
return 'medium';
|
|
434
|
-
case AXPSystemStatuses.Approved.name:
|
|
435
|
-
return 'lowest';
|
|
436
|
-
case AXPSystemStatuses.Rejected.name:
|
|
437
|
-
return 'high';
|
|
438
|
-
default:
|
|
439
|
-
return 'medium';
|
|
440
|
-
}
|
|
441
|
-
}
|
|
895
|
+
//#endregion
|
|
896
|
+
//#region ---- Component ----
|
|
442
897
|
getComponent() {
|
|
443
898
|
return () => import('./acorex-modules-human-capital-management-leave-request-task-popover.component-yGvT9kSL.mjs').then((m) => m.AXMLeaveRequestTaskPopoverComponent);
|
|
444
899
|
}
|
|
@@ -924,7 +1379,7 @@ class AXMHumanCapitalModuleEntityProvider {
|
|
|
924
1379
|
case RootConfig.entities.leaveType.name:
|
|
925
1380
|
return (await import('./acorex-modules-human-capital-management-leave-type.entity-CY81Nohl.mjs')).factory();
|
|
926
1381
|
case RootConfig.entities.leaveRequest.name:
|
|
927
|
-
return (await import('./acorex-modules-human-capital-management-leave-request.entity-
|
|
1382
|
+
return (await import('./acorex-modules-human-capital-management-leave-request.entity-Dn2LLbuq.mjs')).factory();
|
|
928
1383
|
}
|
|
929
1384
|
}
|
|
930
1385
|
return null;
|