@rytass/bpm-core-nestjs-module 0.5.1 → 0.7.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.
- package/CHANGELOG.md +52 -0
- package/README.md +2 -0
- package/package.json +10 -3
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/index.js.map +1 -1
- package/src/lib/bpm/bpm-root.module.d.ts +18 -0
- package/src/lib/bpm/bpm-root.module.js +8 -0
- package/src/lib/bpm/bpm-root.module.js.map +1 -1
- package/src/lib/calendar/business-calendar.provider.d.ts +11 -0
- package/src/lib/calendar/business-calendar.provider.js +20 -0
- package/src/lib/calendar/business-calendar.provider.js.map +1 -0
- package/src/lib/calendar/business-calendar.token.d.ts +38 -0
- package/src/lib/calendar/business-calendar.token.js +5 -0
- package/src/lib/calendar/business-calendar.token.js.map +1 -0
- package/src/lib/calendar/calendar.module.d.ts +18 -0
- package/src/lib/calendar/calendar.module.js +32 -0
- package/src/lib/calendar/calendar.module.js.map +1 -0
- package/src/lib/calendar/index.d.ts +5 -0
- package/src/lib/calendar/index.js +9 -0
- package/src/lib/calendar/index.js.map +1 -0
- package/src/lib/calendar/sla-schedule.service.d.ts +33 -0
- package/src/lib/calendar/sla-schedule.service.js +94 -0
- package/src/lib/calendar/sla-schedule.service.js.map +1 -0
- package/src/lib/calendar/weekday-business-calendar.d.ts +15 -0
- package/src/lib/calendar/weekday-business-calendar.js +28 -0
- package/src/lib/calendar/weekday-business-calendar.js.map +1 -0
- package/src/lib/common/iso-duration.d.ts +11 -0
- package/src/lib/common/iso-duration.js +13 -4
- package/src/lib/common/iso-duration.js.map +1 -1
- package/src/lib/notification/notification-options.d.ts +10 -0
- package/src/lib/notification/notification-options.js +19 -0
- package/src/lib/notification/notification-options.js.map +1 -1
- package/src/lib/notification/notification.enums.d.ts +13 -0
- package/src/lib/notification/notification.enums.js +14 -1
- package/src/lib/notification/notification.enums.js.map +1 -1
- package/src/lib/notification/notification.service.d.ts +8 -0
- package/src/lib/notification/notification.service.js +19 -1
- package/src/lib/notification/notification.service.js.map +1 -1
- package/src/lib/template/workflow-definition.validator.js +75 -1
- package/src/lib/template/workflow-definition.validator.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.service.d.ts +21 -3
- package/src/lib/workflow-engine/workflow-engine.service.js +115 -41
- package/src/lib/workflow-engine/workflow-engine.service.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.tokens.d.ts +2 -1
- package/src/lib/workflow-engine/workflow-engine.tokens.js.map +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WorkflowEngineService = void 0;
|
|
3
|
+
exports.WorkflowEngineService = exports.MANUAL_TRANSFER_DELEGATION_REASON = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const common_1 = require("@nestjs/common");
|
|
6
6
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
@@ -9,6 +9,7 @@ const attachment_service_1 = require("../attachment/attachment.service");
|
|
|
9
9
|
const delegation_service_1 = require("../delegation/delegation.service");
|
|
10
10
|
const form_definition_version_entity_1 = require("../form/form-definition-version.entity");
|
|
11
11
|
const form_enums_1 = require("../form/form.enums");
|
|
12
|
+
const sla_schedule_service_1 = require("../calendar/sla-schedule.service");
|
|
12
13
|
const notification_service_1 = require("../notification/notification.service");
|
|
13
14
|
const notification_entity_1 = require("../notification/notification.entity");
|
|
14
15
|
const notification_enums_1 = require("../notification/notification.enums");
|
|
@@ -36,6 +37,11 @@ const workflow_token_entity_1 = require("./workflow-token.entity");
|
|
|
36
37
|
const MAX_PROCESSING_STEPS = 500;
|
|
37
38
|
const DEFAULT_APPROVAL_HISTORY_TASK_LIMIT = 50;
|
|
38
39
|
const SYSTEM_DRY_RUN_INSTANCE_ID = 'dry-run-instance';
|
|
40
|
+
/**
|
|
41
|
+
* Delegation-chain reason recorded for an approver-initiated transfer, as
|
|
42
|
+
* opposed to {@link SLA_ESCALATION_DELEGATION_REASON}.
|
|
43
|
+
*/
|
|
44
|
+
exports.MANUAL_TRANSFER_DELEGATION_REASON = 'MANUAL_TRANSFER';
|
|
39
45
|
const WORKFLOW_READ_ALL_PERMISSIONS = new Set([
|
|
40
46
|
'bpm:*',
|
|
41
47
|
'bpm.workflow.read_all',
|
|
@@ -43,7 +49,7 @@ const WORKFLOW_READ_ALL_PERMISSIONS = new Set([
|
|
|
43
49
|
'workflow.read_all',
|
|
44
50
|
]);
|
|
45
51
|
let WorkflowEngineService = class WorkflowEngineService {
|
|
46
|
-
constructor(approvalInstanceRepository, workflowTokenRepository, taskRepository, taskCandidateRepository, taskDecisionRepository, notificationRepository, activityLogRepository, adhocDirectiveRepository, approvalTemplateRepository, approvalTemplateVersionRepository, formDefinitionVersionRepository, attachmentService, conditionService, delegationService, notificationService, signatureService, serviceTaskDispatcher = new workflow_service_task_dispatcher_token_1.DefaultWorkflowServiceTaskDispatcher()) {
|
|
52
|
+
constructor(approvalInstanceRepository, workflowTokenRepository, taskRepository, taskCandidateRepository, taskDecisionRepository, notificationRepository, activityLogRepository, adhocDirectiveRepository, approvalTemplateRepository, approvalTemplateVersionRepository, formDefinitionVersionRepository, attachmentService, conditionService, delegationService, notificationService, signatureService, slaScheduleService, serviceTaskDispatcher = new workflow_service_task_dispatcher_token_1.DefaultWorkflowServiceTaskDispatcher()) {
|
|
47
53
|
this.approvalInstanceRepository = approvalInstanceRepository;
|
|
48
54
|
this.workflowTokenRepository = workflowTokenRepository;
|
|
49
55
|
this.taskRepository = taskRepository;
|
|
@@ -60,6 +66,7 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
60
66
|
this.delegationService = delegationService;
|
|
61
67
|
this.notificationService = notificationService;
|
|
62
68
|
this.signatureService = signatureService;
|
|
69
|
+
this.slaScheduleService = slaScheduleService;
|
|
63
70
|
this.serviceTaskDispatcher = serviceTaskDispatcher;
|
|
64
71
|
}
|
|
65
72
|
async submitApprovalInstance(input) {
|
|
@@ -169,7 +176,7 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
169
176
|
await this.processRunningInstance(manager, instance);
|
|
170
177
|
});
|
|
171
178
|
}
|
|
172
|
-
async decideTask(input) {
|
|
179
|
+
async decideTask(input, options = {}) {
|
|
173
180
|
return this.approvalInstanceRepository.manager.transaction(async (manager) => {
|
|
174
181
|
const taskRepository = manager.getRepository(task_entity_1.TaskEntity);
|
|
175
182
|
const taskCandidateRepository = manager.getRepository(task_candidate_entity_1.TaskCandidateEntity);
|
|
@@ -223,6 +230,14 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
223
230
|
const returnToNodeId = input.action === workflow_engine_enums_1.TaskDecisionActionEnum.RETURNED
|
|
224
231
|
? readReturnTargetNodeId(instance.workflowSnapshot, task.nodeId, input.returnToNodeId)
|
|
225
232
|
: null;
|
|
233
|
+
// Read from the instance snapshot, not the live template: templates
|
|
234
|
+
// that turn `requireComment` on later must not retroactively block
|
|
235
|
+
// in-flight instances started against the previous version.
|
|
236
|
+
if (input.action === workflow_engine_enums_1.TaskDecisionActionEnum.RETURNED &&
|
|
237
|
+
!decisionComment &&
|
|
238
|
+
isReturnCommentRequired(instance.workflowSnapshot, task.nodeId)) {
|
|
239
|
+
throw new common_1.BadRequestException(`Return decision comment is required by workflow node ${task.nodeId}`);
|
|
240
|
+
}
|
|
226
241
|
const decidedAt = new Date();
|
|
227
242
|
const claimedTask = await taskRepository.save({
|
|
228
243
|
...task,
|
|
@@ -261,7 +276,7 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
261
276
|
transferToMemberId,
|
|
262
277
|
}));
|
|
263
278
|
if (input.action === workflow_engine_enums_1.TaskDecisionActionEnum.TRANSFERRED) {
|
|
264
|
-
await this.transferTask(manager, instance, claimedTask, decision, signature, transferToMemberId, decisionComment, decidedAt, claimedCandidate);
|
|
279
|
+
await this.transferTask(manager, instance, claimedTask, decision, signature, transferToMemberId, decisionComment, decidedAt, claimedCandidate, options.transferReason ?? exports.MANUAL_TRANSFER_DELEGATION_REASON);
|
|
265
280
|
await this.notificationService.resolveTaskNotifications({
|
|
266
281
|
actingMemberId: input.decidedByMemberId,
|
|
267
282
|
manager,
|
|
@@ -1895,6 +1910,10 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
1895
1910
|
const candidates = await this.resolveRuntimeTaskCandidates(manager, instance, node);
|
|
1896
1911
|
const primaryCandidate = candidates[0];
|
|
1897
1912
|
const now = new Date();
|
|
1913
|
+
const slaDueAt = await this.slaScheduleService.resolveTaskSlaDueAt({
|
|
1914
|
+
node,
|
|
1915
|
+
now,
|
|
1916
|
+
});
|
|
1898
1917
|
const task = await taskRepository.save(taskRepository.create({
|
|
1899
1918
|
assigneeMemberId: candidates.length === 1 ? primaryCandidate.memberId : null,
|
|
1900
1919
|
assignmentType: candidates.length === 1
|
|
@@ -1908,7 +1927,7 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
1908
1927
|
nodeId: node.id,
|
|
1909
1928
|
openedAt: null,
|
|
1910
1929
|
originalAssigneeMemberId: candidates.length === 1 ? primaryCandidate.originalMemberId : null,
|
|
1911
|
-
slaDueAt
|
|
1930
|
+
slaDueAt,
|
|
1912
1931
|
status: workflow_engine_enums_1.TaskStatusEnum.PENDING,
|
|
1913
1932
|
tokenId: token.id,
|
|
1914
1933
|
}));
|
|
@@ -2006,7 +2025,7 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2006
2025
|
}
|
|
2007
2026
|
return nextCandidates;
|
|
2008
2027
|
}
|
|
2009
|
-
async transferTask(manager, instance, task, decision, signature, transferToMemberId, decisionComment, decidedAt, actorCandidate) {
|
|
2028
|
+
async transferTask(manager, instance, task, decision, signature, transferToMemberId, decisionComment, decidedAt, actorCandidate, transferReason) {
|
|
2010
2029
|
if (!transferToMemberId) {
|
|
2011
2030
|
throw new common_1.BadRequestException('Transfer target member is required');
|
|
2012
2031
|
}
|
|
@@ -2021,7 +2040,7 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2021
2040
|
...readDelegationSteps(task.delegationChain),
|
|
2022
2041
|
{
|
|
2023
2042
|
from: transferringMemberId,
|
|
2024
|
-
reason:
|
|
2043
|
+
reason: transferReason,
|
|
2025
2044
|
ruleId: null,
|
|
2026
2045
|
to: transferToMemberId,
|
|
2027
2046
|
},
|
|
@@ -2161,9 +2180,9 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2161
2180
|
return this.resolveOrgUnitPositionCandidates(manager, resolver.orgUnitId, resolver.positionId, Boolean(resolver.includeDescendants), label).then((memberIds) => memberIds.map((memberId) => ({ memberId, sourceType: resolver.type })));
|
|
2162
2181
|
}
|
|
2163
2182
|
if (resolver.type === 'ORG_UNIT_MANAGER') {
|
|
2164
|
-
return this.resolveOrgUnitManagerCandidates(manager, instance, resolver.orgUnitId, resolver.fallback, label).then((memberIds) => memberIds.map((memberId) => ({ memberId, sourceType: resolver.type })));
|
|
2183
|
+
return this.resolveOrgUnitManagerCandidates(manager, instance, resolver.orgUnitId, resolver.fallback, label, resolver.preferClosestOrgUnit === true).then((memberIds) => memberIds.map((memberId) => ({ memberId, sourceType: resolver.type })));
|
|
2165
2184
|
}
|
|
2166
|
-
return this.resolveInitiatorManagerCandidates(manager, instance, resolver.levelsUp, resolver.fallback, label).then((memberIds) => memberIds.map((memberId) => ({ memberId, sourceType: resolver.type })));
|
|
2185
|
+
return this.resolveInitiatorManagerCandidates(manager, instance, resolver.levelsUp, resolver.fallback, label, resolver.preferClosestOrgUnit === true).then((memberIds) => memberIds.map((memberId) => ({ memberId, sourceType: resolver.type })));
|
|
2167
2186
|
}
|
|
2168
2187
|
async resolvePositionCandidates(manager, positionId, label) {
|
|
2169
2188
|
const today = toDateOnlyString(new Date());
|
|
@@ -2184,9 +2203,9 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2184
2203
|
}
|
|
2185
2204
|
return uniqueTexts(activeMemberships.map((membership) => membership.memberId));
|
|
2186
2205
|
}
|
|
2187
|
-
async resolveInitiatorManagerCandidates(manager, instance, levelsUp, fallback, label) {
|
|
2206
|
+
async resolveInitiatorManagerCandidates(manager, instance, levelsUp, fallback, label, preferClosestOrgUnit) {
|
|
2188
2207
|
const normalizedLevelsUp = Math.max(Math.trunc(levelsUp), 1);
|
|
2189
|
-
const resolvedManagerMemberIds = await this.resolveManagerMemberIdsFromOrganization(manager, instance.initiatorMemberId, normalizedLevelsUp);
|
|
2208
|
+
const resolvedManagerMemberIds = await this.resolveManagerMemberIdsFromOrganization(manager, instance.initiatorMemberId, normalizedLevelsUp, preferClosestOrgUnit);
|
|
2190
2209
|
if (resolvedManagerMemberIds.length) {
|
|
2191
2210
|
return resolvedManagerMemberIds;
|
|
2192
2211
|
}
|
|
@@ -2207,18 +2226,18 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2207
2226
|
}
|
|
2208
2227
|
return fallback.memberId;
|
|
2209
2228
|
}
|
|
2210
|
-
async resolveManagerMemberIdsFromOrganization(manager, memberId, levelsUp) {
|
|
2211
|
-
return this.resolveManagerMemberIdsAtLevel(manager, memberId, toDateOnlyString(new Date()), levelsUp);
|
|
2229
|
+
async resolveManagerMemberIdsFromOrganization(manager, memberId, levelsUp, preferClosestOrgUnit) {
|
|
2230
|
+
return this.resolveManagerMemberIdsAtLevel(manager, memberId, toDateOnlyString(new Date()), levelsUp, preferClosestOrgUnit);
|
|
2212
2231
|
}
|
|
2213
|
-
async resolveManagerMemberIdsAtLevel(manager, memberId, date, remainingLevels) {
|
|
2214
|
-
const directManagerMemberIds = await this.resolveDirectManagerMemberIds(manager, memberId, date);
|
|
2232
|
+
async resolveManagerMemberIdsAtLevel(manager, memberId, date, remainingLevels, preferClosestOrgUnit) {
|
|
2233
|
+
const directManagerMemberIds = await this.resolveDirectManagerMemberIds(manager, memberId, date, preferClosestOrgUnit);
|
|
2215
2234
|
if (remainingLevels <= 1 || directManagerMemberIds.length === 0) {
|
|
2216
2235
|
return directManagerMemberIds;
|
|
2217
2236
|
}
|
|
2218
|
-
const nextLevelGroups = await Promise.all(directManagerMemberIds.map((managerMemberId) => this.resolveManagerMemberIdsAtLevel(manager, managerMemberId, date, remainingLevels - 1)));
|
|
2237
|
+
const nextLevelGroups = await Promise.all(directManagerMemberIds.map((managerMemberId) => this.resolveManagerMemberIdsAtLevel(manager, managerMemberId, date, remainingLevels - 1, preferClosestOrgUnit)));
|
|
2219
2238
|
return uniqueTexts(nextLevelGroups.flat());
|
|
2220
2239
|
}
|
|
2221
|
-
async resolveDirectManagerMemberIds(manager, memberId, date) {
|
|
2240
|
+
async resolveDirectManagerMemberIds(manager, memberId, date, preferClosestOrgUnit) {
|
|
2222
2241
|
const memberships = await manager.getRepository(membership_entity_1.MembershipEntity).find({
|
|
2223
2242
|
where: { memberId },
|
|
2224
2243
|
});
|
|
@@ -2227,11 +2246,11 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2227
2246
|
const positionIds = activeMemberships
|
|
2228
2247
|
.map((membership) => membership.positionId)
|
|
2229
2248
|
.filter((positionId) => Boolean(positionId));
|
|
2230
|
-
const
|
|
2249
|
+
const orgUnits = await this.readOrgUnitAndAncestors(manager, directOrgUnitIds);
|
|
2231
2250
|
const candidatePairs = [
|
|
2232
2251
|
{ scopeId: memberId, scopeType: organization_enums_1.ManagerResolutionScopeTypeEnum.MEMBER },
|
|
2233
|
-
...
|
|
2234
|
-
scopeId,
|
|
2252
|
+
...orgUnits.map((orgUnit) => ({
|
|
2253
|
+
scopeId: orgUnit.id,
|
|
2235
2254
|
scopeType: organization_enums_1.ManagerResolutionScopeTypeEnum.ORG_UNIT,
|
|
2236
2255
|
})),
|
|
2237
2256
|
...positionIds.map((scopeId) => ({
|
|
@@ -2239,17 +2258,15 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2239
2258
|
scopeType: organization_enums_1.ManagerResolutionScopeTypeEnum.POSITION,
|
|
2240
2259
|
})),
|
|
2241
2260
|
];
|
|
2242
|
-
return this.resolveManagerResolutionCandidates(manager, candidatePairs, date);
|
|
2261
|
+
return this.resolveManagerResolutionCandidates(manager, candidatePairs, date, readOrgUnitDepthMap(orgUnits), preferClosestOrgUnit);
|
|
2243
2262
|
}
|
|
2244
|
-
async resolveOrgUnitManagerCandidates(manager, instance, orgUnitId, fallback, label) {
|
|
2263
|
+
async resolveOrgUnitManagerCandidates(manager, instance, orgUnitId, fallback, label, preferClosestOrgUnit) {
|
|
2245
2264
|
const date = toDateOnlyString(new Date());
|
|
2246
|
-
const
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
const managerMemberIds = await this.resolveManagerResolutionCandidates(manager, orgUnitIds.map((scopeId) => ({
|
|
2250
|
-
scopeId,
|
|
2265
|
+
const orgUnits = await this.readOrgUnitAndAncestors(manager, [orgUnitId]);
|
|
2266
|
+
const managerMemberIds = await this.resolveManagerResolutionCandidates(manager, orgUnits.map((orgUnit) => ({
|
|
2267
|
+
scopeId: orgUnit.id,
|
|
2251
2268
|
scopeType: organization_enums_1.ManagerResolutionScopeTypeEnum.ORG_UNIT,
|
|
2252
|
-
})), date);
|
|
2269
|
+
})), date, readOrgUnitDepthMap(orgUnits), preferClosestOrgUnit);
|
|
2253
2270
|
if (!managerMemberIds.length) {
|
|
2254
2271
|
return [
|
|
2255
2272
|
this.resolveFallbackAssignee(instance, fallback, label, `找不到指定組織的主管規則`),
|
|
@@ -2257,7 +2274,7 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2257
2274
|
}
|
|
2258
2275
|
return managerMemberIds;
|
|
2259
2276
|
}
|
|
2260
|
-
async
|
|
2277
|
+
async readOrgUnitAndAncestors(manager, orgUnitIds) {
|
|
2261
2278
|
if (!orgUnitIds.length) {
|
|
2262
2279
|
return [];
|
|
2263
2280
|
}
|
|
@@ -2271,9 +2288,9 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2271
2288
|
.andWhere('orgUnit.path @> :path', { path: orgUnit.path })
|
|
2272
2289
|
.getMany()));
|
|
2273
2290
|
const byId = new Map([...directOrgUnits, ...ancestorGroups.flat()].map((orgUnit) => [orgUnit.id, orgUnit]));
|
|
2274
|
-
return [...byId.
|
|
2291
|
+
return [...byId.values()];
|
|
2275
2292
|
}
|
|
2276
|
-
async resolveManagerResolutionCandidates(manager, candidatePairs, date) {
|
|
2293
|
+
async resolveManagerResolutionCandidates(manager, candidatePairs, date, orgUnitDepths, preferClosestOrgUnit) {
|
|
2277
2294
|
const scopeIds = candidatePairs.map((pair) => pair.scopeId);
|
|
2278
2295
|
if (!scopeIds.length) {
|
|
2279
2296
|
return [];
|
|
@@ -2290,12 +2307,13 @@ let WorkflowEngineService = class WorkflowEngineService {
|
|
|
2290
2307
|
]),
|
|
2291
2308
|
},
|
|
2292
2309
|
});
|
|
2310
|
+
const depthLookup = preferClosestOrgUnit ? orgUnitDepths : undefined;
|
|
2293
2311
|
const active = resolutions
|
|
2294
2312
|
.filter((resolution) => candidatePairs.some((pair) => pair.scopeId === resolution.scopeId &&
|
|
2295
2313
|
pair.scopeType === resolution.scopeType))
|
|
2296
2314
|
.filter((resolution) => isDateRangeActive(resolution, date))
|
|
2297
|
-
.sort(compareManagerResolution);
|
|
2298
|
-
return uniqueTexts(active.map((resolution) => resolution.managerMemberId));
|
|
2315
|
+
.sort((left, right) => compareManagerResolution(left, right, depthLookup));
|
|
2316
|
+
return uniqueTexts(readTopPriorityResolutions(active, depthLookup).map((resolution) => resolution.managerMemberId));
|
|
2299
2317
|
}
|
|
2300
2318
|
async resolveOrgUnitMemberCandidates(manager, orgUnitId, includeDescendants, label) {
|
|
2301
2319
|
const orgUnitIds = await this.readOrgUnitScopeIds(manager, orgUnitId, includeDescendants);
|
|
@@ -2716,8 +2734,8 @@ exports.WorkflowEngineService = WorkflowEngineService = tslib_1.__decorate([
|
|
|
2716
2734
|
tslib_1.__param(8, (0, typeorm_1.InjectRepository)(approval_template_entity_1.ApprovalTemplateEntity)),
|
|
2717
2735
|
tslib_1.__param(9, (0, typeorm_1.InjectRepository)(approval_template_version_entity_1.ApprovalTemplateVersionEntity)),
|
|
2718
2736
|
tslib_1.__param(10, (0, typeorm_1.InjectRepository)(form_definition_version_entity_1.FormDefinitionVersionEntity)),
|
|
2719
|
-
tslib_1.__param(
|
|
2720
|
-
tslib_1.__param(
|
|
2737
|
+
tslib_1.__param(17, (0, common_1.Optional)()),
|
|
2738
|
+
tslib_1.__param(17, (0, common_1.Inject)(workflow_service_task_dispatcher_token_1.BPM_WORKFLOW_SERVICE_TASK_DISPATCHER)),
|
|
2721
2739
|
tslib_1.__metadata("design:paramtypes", [typeorm_2.Repository,
|
|
2722
2740
|
typeorm_2.Repository,
|
|
2723
2741
|
typeorm_2.Repository,
|
|
@@ -2733,7 +2751,8 @@ exports.WorkflowEngineService = WorkflowEngineService = tslib_1.__decorate([
|
|
|
2733
2751
|
condition_service_1.ConditionService,
|
|
2734
2752
|
delegation_service_1.DelegationService,
|
|
2735
2753
|
notification_service_1.NotificationService,
|
|
2736
|
-
signature_service_1.SignatureService,
|
|
2754
|
+
signature_service_1.SignatureService,
|
|
2755
|
+
sla_schedule_service_1.BPMSlaScheduleService, Object])
|
|
2737
2756
|
], WorkflowEngineService);
|
|
2738
2757
|
function parseJsonObject(value, label) {
|
|
2739
2758
|
try {
|
|
@@ -2917,6 +2936,11 @@ function readDefaultReturnTargetNodeId(workflow, currentNode) {
|
|
|
2917
2936
|
}
|
|
2918
2937
|
return previousNodeId;
|
|
2919
2938
|
}
|
|
2939
|
+
function isReturnCommentRequired(workflow, nodeId) {
|
|
2940
|
+
const node = readWorkflowNodeOrThrow(workflow, nodeId);
|
|
2941
|
+
return (node.type === 'userTask' &&
|
|
2942
|
+
node.data.returnBehavior.requireComment === true);
|
|
2943
|
+
}
|
|
2920
2944
|
function readReturnResubmitStrategy(task, instance) {
|
|
2921
2945
|
const node = readWorkflowNodeOrThrow(instance.workflowSnapshot, task.nodeId);
|
|
2922
2946
|
if (node.type !== 'userTask') {
|
|
@@ -3289,7 +3313,10 @@ function readManagerMemberIdFromInitiatorSnapshot(initiatorMetadataSnapshot, lev
|
|
|
3289
3313
|
return managerMemberIds[Math.max(levelsUp - 1, 0)];
|
|
3290
3314
|
}
|
|
3291
3315
|
const customFields = initiatorMetadataSnapshot.customFields;
|
|
3292
|
-
|
|
3316
|
+
// An empty `customFields` object must not swallow the top-level fallback:
|
|
3317
|
+
// callers commonly send `{ customFields: {}, managerMemberId: '...' }`, and
|
|
3318
|
+
// returning early there resolves no approver at all.
|
|
3319
|
+
if (isRecord(customFields) && customFields.managerMemberId !== undefined) {
|
|
3293
3320
|
return customFields.managerMemberId;
|
|
3294
3321
|
}
|
|
3295
3322
|
return initiatorMetadataSnapshot.managerMemberId;
|
|
@@ -3298,14 +3325,61 @@ function isDateRangeActive(value, date) {
|
|
|
3298
3325
|
return (value.effectiveFrom <= date &&
|
|
3299
3326
|
(!value.effectiveTo || value.effectiveTo >= date));
|
|
3300
3327
|
}
|
|
3301
|
-
|
|
3328
|
+
/**
|
|
3329
|
+
* Manager resolutions are sorted by priority and then by scope specificity, so
|
|
3330
|
+
* every entry below the winning tier is a lower-precedence fallback that must
|
|
3331
|
+
* not join the approver list — a company-wide catch-all rule would otherwise be
|
|
3332
|
+
* appended to every member's direct manager. The organization module already
|
|
3333
|
+
* resolves managers this way (`OrganizationService.resolveManagerMemberId`
|
|
3334
|
+
* returns `active[0]`); this keeps the workflow engine consistent with it.
|
|
3335
|
+
*
|
|
3336
|
+
* Ties on the winning tier are preserved so a step can still be shared by
|
|
3337
|
+
* several managers of equal precedence.
|
|
3338
|
+
*
|
|
3339
|
+
* When `orgUnitDepths` is provided and the winning scope is ORG_UNIT, only the
|
|
3340
|
+
* deepest org units on the winning tier are kept so that ancestor-level
|
|
3341
|
+
* catch-all rules do not dilute the approver list. This is opt-in via the
|
|
3342
|
+
* resolver's `preferClosestOrgUnit` flag because org-tree depth does not always
|
|
3343
|
+
* reflect authority (e.g. project offices attached to executive roles).
|
|
3344
|
+
*/
|
|
3345
|
+
function readTopPriorityResolutions(resolutions, orgUnitDepths) {
|
|
3346
|
+
const [top] = resolutions;
|
|
3347
|
+
if (!top) {
|
|
3348
|
+
return [];
|
|
3349
|
+
}
|
|
3350
|
+
const sameTier = resolutions.filter((resolution) => resolution.priority === top.priority &&
|
|
3351
|
+
resolution.scopeType === top.scopeType);
|
|
3352
|
+
if (orgUnitDepths &&
|
|
3353
|
+
top.scopeType === organization_enums_1.ManagerResolutionScopeTypeEnum.ORG_UNIT) {
|
|
3354
|
+
const maxDepth = Math.max(...sameTier.map((resolution) => orgUnitDepths.get(resolution.scopeId) ?? 0));
|
|
3355
|
+
return sameTier.filter((resolution) => (orgUnitDepths.get(resolution.scopeId) ?? 0) === maxDepth);
|
|
3356
|
+
}
|
|
3357
|
+
return sameTier;
|
|
3358
|
+
}
|
|
3359
|
+
function compareManagerResolution(left, right, orgUnitDepths) {
|
|
3302
3360
|
const priorityDiff = right.priority - left.priority;
|
|
3303
3361
|
if (priorityDiff !== 0) {
|
|
3304
3362
|
return priorityDiff;
|
|
3305
3363
|
}
|
|
3306
|
-
|
|
3307
|
-
readManagerResolutionScopeRank(left.scopeType)
|
|
3308
|
-
|
|
3364
|
+
const scopeRankDiff = readManagerResolutionScopeRank(right.scopeType) -
|
|
3365
|
+
readManagerResolutionScopeRank(left.scopeType);
|
|
3366
|
+
if (scopeRankDiff !== 0) {
|
|
3367
|
+
return scopeRankDiff;
|
|
3368
|
+
}
|
|
3369
|
+
if (orgUnitDepths) {
|
|
3370
|
+
const depthDiff = (orgUnitDepths.get(right.scopeId) ?? 0) -
|
|
3371
|
+
(orgUnitDepths.get(left.scopeId) ?? 0);
|
|
3372
|
+
if (depthDiff !== 0) {
|
|
3373
|
+
return depthDiff;
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
return right.effectiveFrom.localeCompare(left.effectiveFrom);
|
|
3377
|
+
}
|
|
3378
|
+
function readOrgUnitDepthMap(orgUnits) {
|
|
3379
|
+
return new Map(orgUnits.map((orgUnit) => [
|
|
3380
|
+
orgUnit.id,
|
|
3381
|
+
orgUnit.path.split('.').length,
|
|
3382
|
+
]));
|
|
3309
3383
|
}
|
|
3310
3384
|
function readManagerResolutionScopeRank(scopeType) {
|
|
3311
3385
|
const ranks = {
|