rez_core 4.0.184 → 4.0.187
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/dist/app.module.js +11 -0
- package/dist/app.module.js.map +1 -1
- package/dist/config/bull.config.d.ts +10 -0
- package/dist/config/bull.config.js +66 -0
- package/dist/config/bull.config.js.map +1 -0
- package/dist/config/database.config.js +1 -1
- package/dist/config/database.config.js.map +1 -1
- package/dist/module/entity_json/controller/entity_json.controller.d.ts +8 -0
- package/dist/module/entity_json/controller/entity_json.controller.js +43 -0
- package/dist/module/entity_json/controller/entity_json.controller.js.map +1 -0
- package/dist/module/entity_json/entity_json.module.d.ts +2 -0
- package/dist/module/entity_json/entity_json.module.js +26 -0
- package/dist/module/entity_json/entity_json.module.js.map +1 -0
- package/dist/module/entity_json/service/entity_json.service.d.ts +7 -0
- package/dist/module/entity_json/service/entity_json.service.js +116 -0
- package/dist/module/entity_json/service/entity_json.service.js.map +1 -0
- package/dist/module/filter/service/filter.service.js.map +1 -1
- package/dist/module/integration/service/wrapper.service.d.ts +3 -1
- package/dist/module/integration/service/wrapper.service.js +39 -36
- package/dist/module/integration/service/wrapper.service.js.map +1 -1
- package/dist/module/linked_attributes/controller/linked_attributes.controller.d.ts +5 -0
- package/dist/module/linked_attributes/controller/linked_attributes.controller.js +29 -0
- package/dist/module/linked_attributes/controller/linked_attributes.controller.js.map +1 -0
- package/dist/module/linked_attributes/entity/linked_attribute.entity.d.ts +9 -0
- package/dist/module/linked_attributes/entity/linked_attribute.entity.js +70 -0
- package/dist/module/linked_attributes/entity/linked_attribute.entity.js.map +1 -0
- package/dist/module/linked_attributes/linked_attributes.module.d.ts +2 -0
- package/dist/module/linked_attributes/linked_attributes.module.js +29 -0
- package/dist/module/linked_attributes/linked_attributes.module.js.map +1 -0
- package/dist/module/linked_attributes/repository/linked_attribute.repository.d.ts +6 -0
- package/dist/module/linked_attributes/repository/linked_attribute.repository.js +31 -0
- package/dist/module/linked_attributes/repository/linked_attribute.repository.js.map +1 -0
- package/dist/module/linked_attributes/service/linked_attributes.service.d.ts +5 -0
- package/dist/module/linked_attributes/service/linked_attributes.service.js +34 -0
- package/dist/module/linked_attributes/service/linked_attributes.service.js.map +1 -0
- package/dist/module/mapper/service/field-mapper.service.js +2 -2
- package/dist/module/mapper/service/field-mapper.service.js.map +1 -1
- package/dist/module/meta/controller/attribute-master.controller.d.ts +10 -1
- package/dist/module/meta/controller/attribute-master.controller.js +27 -2
- package/dist/module/meta/controller/attribute-master.controller.js.map +1 -1
- package/dist/module/meta/controller/entity-master.controller.d.ts +6 -0
- package/dist/module/meta/controller/entity-master.controller.js +13 -0
- package/dist/module/meta/controller/entity-master.controller.js.map +1 -1
- package/dist/module/meta/entity.module.js +7 -0
- package/dist/module/meta/entity.module.js.map +1 -1
- package/dist/module/meta/repository/attribute-master.repository.d.ts +4 -0
- package/dist/module/meta/repository/attribute-master.repository.js +19 -0
- package/dist/module/meta/repository/attribute-master.repository.js.map +1 -1
- package/dist/module/meta/repository/entity-attribute-update.repository.d.ts +6 -0
- package/dist/module/meta/repository/entity-attribute-update.repository.js +44 -0
- package/dist/module/meta/repository/entity-attribute-update.repository.js.map +1 -0
- package/dist/module/meta/repository/entity-master.repository.d.ts +7 -1
- package/dist/module/meta/repository/entity-master.repository.js +24 -2
- package/dist/module/meta/repository/entity-master.repository.js.map +1 -1
- package/dist/module/meta/service/attribute-master.service.d.ts +4 -0
- package/dist/module/meta/service/attribute-master.service.js +3 -0
- package/dist/module/meta/service/attribute-master.service.js.map +1 -1
- package/dist/module/meta/service/entity-attribute-update.service.d.ts +7 -0
- package/dist/module/meta/service/entity-attribute-update.service.js +35 -0
- package/dist/module/meta/service/entity-attribute-update.service.js.map +1 -0
- package/dist/module/meta/service/entity-master.service.d.ts +4 -0
- package/dist/module/meta/service/entity-master.service.js +3 -0
- package/dist/module/meta/service/entity-master.service.js.map +1 -1
- package/dist/module/meta/service/resolver.service.js +2 -2
- package/dist/module/meta/service/resolver.service.js.map +1 -1
- package/dist/module/module/service/module-access.service.js +1 -7
- package/dist/module/module/service/module-access.service.js.map +1 -1
- package/dist/module/workflow/entity/action.entity.d.ts +1 -0
- package/dist/module/workflow/entity/action.entity.js +4 -0
- package/dist/module/workflow/entity/action.entity.js.map +1 -1
- package/dist/module/workflow/repository/action-data.repository.js +1 -0
- package/dist/module/workflow/repository/action-data.repository.js.map +1 -1
- package/dist/module/workflow/repository/task.repository.d.ts +3 -1
- package/dist/module/workflow/repository/task.repository.js +6 -1
- package/dist/module/workflow/repository/task.repository.js.map +1 -1
- package/dist/module/workflow/service/task.service.js +41 -27
- package/dist/module/workflow/service/task.service.js.map +1 -1
- package/dist/module/workflow/service/workflow-meta.service.js +23 -21
- package/dist/module/workflow/service/workflow-meta.service.js.map +1 -1
- package/dist/module/workflow-automation/controller/workflow-automation.controller.d.ts +6 -0
- package/dist/module/workflow-automation/controller/workflow-automation.controller.js +16 -0
- package/dist/module/workflow-automation/controller/workflow-automation.controller.js.map +1 -1
- package/dist/module/workflow-automation/entity/workflow-automation.entity.d.ts +2 -0
- package/dist/module/workflow-automation/entity/workflow-automation.entity.js +8 -0
- package/dist/module/workflow-automation/entity/workflow-automation.entity.js.map +1 -1
- package/dist/module/workflow-automation/service/schedule-handler.service.d.ts +16 -0
- package/dist/module/workflow-automation/service/schedule-handler.service.js +109 -0
- package/dist/module/workflow-automation/service/schedule-handler.service.js.map +1 -0
- package/dist/module/workflow-automation/service/workflow-automation-engine.service.d.ts +1 -1
- package/dist/module/workflow-automation/service/workflow-automation-engine.service.js.map +1 -1
- package/dist/module/workflow-automation/service/workflow-automation.service.d.ts +13 -1
- package/dist/module/workflow-automation/service/workflow-automation.service.js +111 -2
- package/dist/module/workflow-automation/service/workflow-automation.service.js.map +1 -1
- package/dist/module/workflow-automation/workflow-automation.module.js +14 -1
- package/dist/module/workflow-automation/workflow-automation.module.js.map +1 -1
- package/dist/module/workflow-schedule/constants/schedule.constants.d.ts +27 -0
- package/dist/module/workflow-schedule/constants/schedule.constants.js +31 -0
- package/dist/module/workflow-schedule/constants/schedule.constants.js.map +1 -0
- package/dist/module/workflow-schedule/controller/workflow-schedule.controller.d.ts +83 -0
- package/dist/module/workflow-schedule/controller/workflow-schedule.controller.js +220 -0
- package/dist/module/workflow-schedule/controller/workflow-schedule.controller.js.map +1 -0
- package/dist/module/workflow-schedule/dto/create-schedule.dto.d.ts +32 -0
- package/dist/module/workflow-schedule/dto/create-schedule.dto.js +163 -0
- package/dist/module/workflow-schedule/dto/create-schedule.dto.js.map +1 -0
- package/dist/module/workflow-schedule/dto/get-execution-logs.dto.d.ts +35 -0
- package/dist/module/workflow-schedule/dto/get-execution-logs.dto.js +124 -0
- package/dist/module/workflow-schedule/dto/get-execution-logs.dto.js.map +1 -0
- package/dist/module/workflow-schedule/dto/update-schedule.dto.d.ts +19 -0
- package/dist/module/workflow-schedule/dto/update-schedule.dto.js +106 -0
- package/dist/module/workflow-schedule/dto/update-schedule.dto.js.map +1 -0
- package/dist/module/workflow-schedule/entities/scheduled-workflow.entity.d.ts +30 -0
- package/dist/module/workflow-schedule/entities/scheduled-workflow.entity.js +113 -0
- package/dist/module/workflow-schedule/entities/scheduled-workflow.entity.js.map +1 -0
- package/dist/module/workflow-schedule/entities/workflow-execution-log.entity.d.ts +34 -0
- package/dist/module/workflow-schedule/entities/workflow-execution-log.entity.js +118 -0
- package/dist/module/workflow-schedule/entities/workflow-execution-log.entity.js.map +1 -0
- package/dist/module/workflow-schedule/interfaces/schedule-job-data.interface.d.ts +44 -0
- package/dist/module/workflow-schedule/interfaces/schedule-job-data.interface.js +3 -0
- package/dist/module/workflow-schedule/interfaces/schedule-job-data.interface.js.map +1 -0
- package/dist/module/workflow-schedule/interfaces/workflow-schedule-options.interface.d.ts +3 -0
- package/dist/module/workflow-schedule/interfaces/workflow-schedule-options.interface.js +3 -0
- package/dist/module/workflow-schedule/interfaces/workflow-schedule-options.interface.js.map +1 -0
- package/dist/module/workflow-schedule/processors/schedule.processor.d.ts +31 -0
- package/dist/module/workflow-schedule/processors/schedule.processor.js +409 -0
- package/dist/module/workflow-schedule/processors/schedule.processor.js.map +1 -0
- package/dist/module/workflow-schedule/service/workflow-schedule.service.d.ts +44 -0
- package/dist/module/workflow-schedule/service/workflow-schedule.service.js +434 -0
- package/dist/module/workflow-schedule/service/workflow-schedule.service.js.map +1 -0
- package/dist/module/workflow-schedule/workflow-schedule.module.d.ts +5 -0
- package/dist/module/workflow-schedule/workflow-schedule.module.js +52 -0
- package/dist/module/workflow-schedule/workflow-schedule.module.js.map +1 -0
- package/dist/table.config.d.ts +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/service/loggingUtil.service.d.ts +9 -2
- package/dist/utils/service/loggingUtil.service.js +65 -14
- package/dist/utils/service/loggingUtil.service.js.map +1 -1
- package/dist/utils/utils.module.js +2 -0
- package/dist/utils/utils.module.js.map +1 -1
- package/package.json +9 -4
- package/src/app.module.ts +16 -2
- package/src/config/bull.config.ts +69 -0
- package/src/config/database.config.ts +1 -1
- package/src/module/entity_json/controller/entity_json.controller.ts +47 -0
- package/src/module/entity_json/entity_json.module.ts +13 -0
- package/src/module/entity_json/service/entity_json.service.ts +162 -0
- package/src/module/filter/service/filter.service.ts +0 -2
- package/src/module/integration/service/wrapper.service.ts +248 -41
- package/src/module/linked_attributes/controller/linked_attributes.controller.ts +10 -0
- package/src/module/linked_attributes/entity/linked_attribute.entity.ts +48 -0
- package/src/module/linked_attributes/linked_attributes.module.ts +16 -0
- package/src/module/linked_attributes/repository/linked_attribute.repository.ts +12 -0
- package/src/module/linked_attributes/service/linked_attributes.service.ts +22 -0
- package/src/module/mapper/service/field-mapper.service.ts +12 -7
- package/src/module/meta/controller/attribute-master.controller.ts +20 -0
- package/src/module/meta/controller/entity-master.controller.ts +13 -0
- package/src/module/meta/entity.module.ts +8 -0
- package/src/module/meta/repository/attribute-master.repository.ts +20 -0
- package/src/module/meta/repository/entity-attribute-update.repository.ts +44 -0
- package/src/module/meta/repository/entity-master.repository.ts +30 -0
- package/src/module/meta/service/attribute-master.service.ts +4 -0
- package/src/module/meta/service/entity-attribute-update.service.ts +29 -0
- package/src/module/meta/service/entity-master.service.ts +6 -0
- package/src/module/meta/service/resolver.service.ts +2 -2
- package/src/module/module/service/module-access.service.ts +3 -16
- package/src/module/workflow/entity/action.entity.ts +3 -0
- package/src/module/workflow/repository/action-data.repository.ts +1 -0
- package/src/module/workflow/repository/task.repository.ts +8 -0
- package/src/module/workflow/service/task.service.ts +47 -38
- package/src/module/workflow/service/workflow-meta.service.ts +47 -33
- package/src/module/workflow-automation/SCHEDULING_GUIDE.md +145 -0
- package/src/module/workflow-automation/controller/workflow-automation.controller.ts +22 -0
- package/src/module/workflow-automation/entity/workflow-automation.entity.ts +5 -0
- package/src/module/workflow-automation/service/schedule-handler.service.ts +149 -0
- package/src/module/workflow-automation/service/workflow-automation-engine.service.ts +1 -1
- package/src/module/workflow-automation/service/workflow-automation.service.ts +163 -2
- package/src/module/workflow-automation/workflow-automation.module.ts +14 -1
- package/src/module/workflow-schedule/INSTALLATION.md +244 -0
- package/src/module/workflow-schedule/MULTI_PROJECT_GUIDE.md +196 -0
- package/src/module/workflow-schedule/README.md +422 -0
- package/src/module/workflow-schedule/constants/schedule.constants.ts +48 -0
- package/src/module/workflow-schedule/controller/workflow-schedule.controller.ts +255 -0
- package/src/module/workflow-schedule/docs/CLAUDE_CODE_GUIDE.md +510 -0
- package/src/module/workflow-schedule/docs/CLAUDE_CODE_PROMPT.md +362 -0
- package/src/module/workflow-schedule/docs/RUN_CLAUDE_CODE.sh +68 -0
- package/src/module/workflow-schedule/dto/create-schedule.dto.ts +147 -0
- package/src/module/workflow-schedule/dto/get-execution-logs.dto.ts +119 -0
- package/src/module/workflow-schedule/dto/update-schedule.dto.ts +96 -0
- package/src/module/workflow-schedule/entities/scheduled-workflow.entity.ts +148 -0
- package/src/module/workflow-schedule/entities/workflow-execution-log.entity.ts +154 -0
- package/src/module/workflow-schedule/interfaces/schedule-job-data.interface.ts +53 -0
- package/src/module/workflow-schedule/interfaces/workflow-schedule-options.interface.ts +12 -0
- package/src/module/workflow-schedule/processors/schedule.processor.ts +584 -0
- package/src/module/workflow-schedule/service/workflow-schedule.service.ts +600 -0
- package/src/module/workflow-schedule/workflow-schedule.module.ts +67 -0
- package/src/resources/dev.properties.yaml +1 -1
- package/src/utils/service/loggingUtil.service.ts +70 -16
- package/src/utils/utils.module.ts +2 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Workflow Automation Scheduling Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
This module integrates with `WorkflowScheduleModule` to enable creating scheduled workflow automations. You can create schedules that run automatically via cron, or create them in a disabled state for manual triggering only.
|
|
5
|
+
|
|
6
|
+
## Controlling Auto-Scheduling Behavior
|
|
7
|
+
|
|
8
|
+
### Option 1: Create Schedules WITHOUT Auto-Execution
|
|
9
|
+
When creating a schedule, set `is_enabled: false` to prevent it from running automatically:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Inject WorkflowScheduleService in your controller/service
|
|
13
|
+
constructor(
|
|
14
|
+
private readonly workflowScheduleService: WorkflowScheduleService,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
// Create schedule without auto-execution
|
|
18
|
+
const schedule = await this.workflowScheduleService.createSchedule(
|
|
19
|
+
{
|
|
20
|
+
workflow_id: workflowId,
|
|
21
|
+
workflow_name: 'My Workflow',
|
|
22
|
+
name: 'My Schedule',
|
|
23
|
+
cron_expression: '0 9 * * *', // Every day at 9 AM
|
|
24
|
+
timezone: 'America/New_York',
|
|
25
|
+
is_enabled: false, // 👈 This prevents auto-execution
|
|
26
|
+
// ... other fields
|
|
27
|
+
},
|
|
28
|
+
loggedInUser,
|
|
29
|
+
);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Option 2: Create Schedules WITH Auto-Execution
|
|
33
|
+
Simply set `is_enabled: true` (or omit it, as it defaults to true):
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
const schedule = await this.workflowScheduleService.createSchedule(
|
|
37
|
+
{
|
|
38
|
+
workflow_id: workflowId,
|
|
39
|
+
workflow_name: 'My Workflow',
|
|
40
|
+
name: 'My Schedule',
|
|
41
|
+
cron_expression: '0 9 * * *',
|
|
42
|
+
timezone: 'America/New_York',
|
|
43
|
+
is_enabled: true, // 👈 Schedule will run automatically on cron
|
|
44
|
+
// ... other fields
|
|
45
|
+
},
|
|
46
|
+
loggedInUser,
|
|
47
|
+
);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## How It Works
|
|
51
|
+
|
|
52
|
+
The scheduling logic in `WorkflowScheduleService.createSchedule()` (line 101-103) only adds jobs to the Bull queue if:
|
|
53
|
+
1. `is_enabled === true`
|
|
54
|
+
2. `schedule_status === 'ACTIVE'`
|
|
55
|
+
|
|
56
|
+
If either condition is false, the schedule is saved to the database but NOT added to the queue, meaning the cron processor won't execute it.
|
|
57
|
+
|
|
58
|
+
## Manual Triggering
|
|
59
|
+
|
|
60
|
+
You can manually trigger any schedule (enabled or disabled) using:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const result = await this.workflowScheduleService.triggerManualExecution(
|
|
64
|
+
scheduleId,
|
|
65
|
+
loggedInUser,
|
|
66
|
+
{ /* optional metadata */ },
|
|
67
|
+
);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Enabling/Disabling Schedules Later
|
|
71
|
+
|
|
72
|
+
### To Enable a Disabled Schedule:
|
|
73
|
+
```typescript
|
|
74
|
+
await this.workflowScheduleService.updateSchedule(
|
|
75
|
+
{
|
|
76
|
+
id: scheduleId,
|
|
77
|
+
is_enabled: true,
|
|
78
|
+
},
|
|
79
|
+
loggedInUser,
|
|
80
|
+
);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### To Disable an Active Schedule:
|
|
84
|
+
```typescript
|
|
85
|
+
await this.workflowScheduleService.updateSchedule(
|
|
86
|
+
{
|
|
87
|
+
id: scheduleId,
|
|
88
|
+
is_enabled: false,
|
|
89
|
+
},
|
|
90
|
+
loggedInUser,
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### To Pause a Schedule Temporarily:
|
|
95
|
+
```typescript
|
|
96
|
+
await this.workflowScheduleService.pauseSchedule(scheduleId, loggedInUser);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### To Resume a Paused Schedule:
|
|
100
|
+
```typescript
|
|
101
|
+
await this.workflowScheduleService.resumeSchedule(scheduleId, loggedInUser);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Best Practices
|
|
105
|
+
|
|
106
|
+
1. **Testing**: Create schedules with `is_enabled: false` during development and testing
|
|
107
|
+
2. **Staged Rollout**: Create schedules disabled, test manually, then enable when ready
|
|
108
|
+
3. **Monitoring**: Use `getExecutionLogs()` and `getExecutionStats()` to monitor schedule performance
|
|
109
|
+
4. **Cleanup**: Use `deleteSchedule()` to soft-delete schedules you no longer need
|
|
110
|
+
|
|
111
|
+
## Example: Complete Workflow
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// 1. Create schedule (disabled)
|
|
115
|
+
const schedule = await this.workflowScheduleService.createSchedule({
|
|
116
|
+
workflow_id: 123,
|
|
117
|
+
workflow_name: 'Send Daily Report',
|
|
118
|
+
name: 'Daily Report Schedule',
|
|
119
|
+
cron_expression: '0 9 * * *',
|
|
120
|
+
is_enabled: false, // Start disabled
|
|
121
|
+
}, loggedInUser);
|
|
122
|
+
|
|
123
|
+
// 2. Test manually
|
|
124
|
+
const testResult = await this.workflowScheduleService.triggerManualExecution(
|
|
125
|
+
schedule.id,
|
|
126
|
+
loggedInUser,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// 3. Check execution logs
|
|
130
|
+
const logs = await this.workflowScheduleService.getExecutionLogs({
|
|
131
|
+
schedule_id: schedule.id,
|
|
132
|
+
}, loggedInUser);
|
|
133
|
+
|
|
134
|
+
// 4. If tests pass, enable for auto-execution
|
|
135
|
+
if (logs.data[0].execution_status === 'COMPLETED') {
|
|
136
|
+
await this.workflowScheduleService.updateSchedule({
|
|
137
|
+
id: schedule.id,
|
|
138
|
+
is_enabled: true, // Now it will run on cron
|
|
139
|
+
}, loggedInUser);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Environment Configuration
|
|
144
|
+
|
|
145
|
+
The Bull queue (Redis) connection is configured in `src/config/bull.config.ts`. Ensure Redis is running and accessible for the scheduler to work.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BadRequestException,
|
|
2
3
|
Body,
|
|
3
4
|
Controller,
|
|
4
5
|
HttpCode,
|
|
@@ -18,4 +19,25 @@ export class WorkflowAutomationController {
|
|
|
18
19
|
@Inject('WorkflowAutomationService')
|
|
19
20
|
private readonly workflowAutomationService: WorkflowAutomationService,
|
|
20
21
|
) {}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Endpoint to update the sequence of workflow automations.
|
|
25
|
+
* Accepts an array of objects with `id` and `sequence`.
|
|
26
|
+
*/
|
|
27
|
+
@Post('/updateSequence')
|
|
28
|
+
@HttpCode(HttpStatus.OK)
|
|
29
|
+
async updateSequence(
|
|
30
|
+
@Body() body: any,
|
|
31
|
+
@Req() req: Request & { user?: any },
|
|
32
|
+
) {
|
|
33
|
+
const loggedInUser = req.user?.userData;
|
|
34
|
+
|
|
35
|
+
if (!Array.isArray(body) || body.length === 0) {
|
|
36
|
+
throw new BadRequestException(
|
|
37
|
+
'Invalid input. Expected a non-empty array.',
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return this.workflowAutomationService.updateSequence(body, loggedInUser);
|
|
42
|
+
}
|
|
21
43
|
}
|
|
@@ -32,4 +32,9 @@ export class WorkflowAutomation extends BaseEntity {
|
|
|
32
32
|
|
|
33
33
|
@Column({ type: 'json', nullable: true })
|
|
34
34
|
schedule: string;
|
|
35
|
+
|
|
36
|
+
@Column({ type: 'varchar', nullable: true })
|
|
37
|
+
cron_type: string;
|
|
38
|
+
@Column({ type: 'int', nullable: true })
|
|
39
|
+
sequence: number;
|
|
35
40
|
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Inject, Injectable, Logger } from '@nestjs/common';
|
|
2
|
+
import { FilterEvaluatorService } from 'src/module/filter/service/filter-evaluator.service';
|
|
3
|
+
import { DataSource } from 'typeorm';
|
|
4
|
+
import { WorkflowAutomationEngineService } from './workflow-automation-engine.service';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class ScheduleHandlerService {
|
|
8
|
+
private readonly logger = new Logger(ScheduleHandlerService.name);
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
private readonly dataSource: DataSource,
|
|
12
|
+
private readonly filterEvaluator: FilterEvaluatorService,
|
|
13
|
+
// @Inject('WorkflowAutomationEngineService')
|
|
14
|
+
private readonly workflowAutomationEngineService: WorkflowAutomationEngineService,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
async scheduleQueryBuilder(workflowId: number, jobData: any) {
|
|
18
|
+
// 1️⃣ Fetch workflow automation config
|
|
19
|
+
const [workflow] = await this.dataSource.query(
|
|
20
|
+
`SELECT * FROM frm_wf_automation WHERE id = ? AND organization_id = ?`,
|
|
21
|
+
[workflowId, jobData.organizationId],
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
if (!workflow) throw new Error(`Workflow with ID ${workflowId} not found`);
|
|
25
|
+
|
|
26
|
+
const event = JSON.parse(workflow.event_json || '{}');
|
|
27
|
+
const scheduleJson = workflow.schedule;
|
|
28
|
+
const entityType = workflow.applicable_entity_type;
|
|
29
|
+
|
|
30
|
+
// 2️⃣ Get table name from frm_entity_master
|
|
31
|
+
const [entity] = await this.dataSource.query(
|
|
32
|
+
`SELECT data_source FROM frm_entity_master WHERE mapped_entity_type = ? AND organization_id = ?`,
|
|
33
|
+
[entityType, jobData.organizationId],
|
|
34
|
+
);
|
|
35
|
+
if (!entity?.data_source) throw new Error(`Entity ${entityType} not found`);
|
|
36
|
+
|
|
37
|
+
const tableName = entity.data_source;
|
|
38
|
+
|
|
39
|
+
// 3️⃣ Resolve executionDate (list master item name)
|
|
40
|
+
const [executionDateItem] = await this.dataSource.query(
|
|
41
|
+
`SELECT name FROM frm_list_master_items WHERE id = ${scheduleJson.executionDate}`
|
|
42
|
+
);
|
|
43
|
+
const executionDateName = executionDateItem?.name?.toLowerCase() || '';
|
|
44
|
+
const executionDataOrTime = scheduleJson.executionDateOrTime;
|
|
45
|
+
|
|
46
|
+
const executionUnits = Number(scheduleJson.executionDateUnits || 0);
|
|
47
|
+
const fixedTime = scheduleJson.fixedTime; // e.g. "16:00"
|
|
48
|
+
|
|
49
|
+
// Build time window logic
|
|
50
|
+
let comparisonDateCondition = '';
|
|
51
|
+
|
|
52
|
+
if (executionDateName.includes('after')) {
|
|
53
|
+
comparisonDateCondition = `
|
|
54
|
+
${executionDataOrTime} >= CURDATE() + INTERVAL ${executionUnits} DAY
|
|
55
|
+
AND ${executionDataOrTime} < CURDATE() + INTERVAL ${executionUnits + 1} DAY
|
|
56
|
+
`;
|
|
57
|
+
} else if (executionDateName.includes('before')) {
|
|
58
|
+
comparisonDateCondition = `
|
|
59
|
+
${executionDataOrTime} >= CURDATE() - INTERVAL ${executionUnits + 1} DAY
|
|
60
|
+
AND ${executionDataOrTime} < CURDATE() - INTERVAL ${executionUnits} DAY
|
|
61
|
+
`;
|
|
62
|
+
} else if (executionDateName.includes('same')) {
|
|
63
|
+
comparisonDateCondition = `
|
|
64
|
+
${executionDataOrTime} >= CURDATE()
|
|
65
|
+
AND ${executionDataOrTime} < CURDATE() + INTERVAL 1 DAY
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const query = `
|
|
70
|
+
SELECT *
|
|
71
|
+
FROM ${tableName}
|
|
72
|
+
WHERE ${comparisonDateCondition}
|
|
73
|
+
AND organization_id = ?
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
this.logger.debug(`Executing Scheduler Query: ${query}`);
|
|
77
|
+
|
|
78
|
+
const results = await this.dataSource.query(query, [
|
|
79
|
+
jobData.organizationId,
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
this.logger.log(
|
|
83
|
+
`Found ${results.length} scheduled records for ${tableName}`,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return { results, workflow, tableName };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ⚙️ Step 2: Handle scheduled automation (main entry point)
|
|
90
|
+
async handleScheduledWorkflow(workflowId: number, jobData: any) {
|
|
91
|
+
const { results, workflow, tableName } = await this.scheduleQueryBuilder(
|
|
92
|
+
workflowId,
|
|
93
|
+
jobData,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (!results?.length) {
|
|
97
|
+
this.logger.warn(`No records found for scheduled workflow ${workflowId}`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.logger.log(
|
|
102
|
+
`Processing ${results.length} records for workflow ${workflowId}`,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Parse the workflow event JSON again to get filter/action info
|
|
106
|
+
const event = JSON.parse(workflow.event_json || '{}');
|
|
107
|
+
const filter = workflow.condition_filter_code;
|
|
108
|
+
const mappedEntityType = workflow.applicable_entity_type;
|
|
109
|
+
|
|
110
|
+
const matchedEntities: any[] = [];
|
|
111
|
+
|
|
112
|
+
// 🔁 Step 2A: Evaluate criteria for each record
|
|
113
|
+
for (const record of results) {
|
|
114
|
+
const entityIdToUse = record.id; // assuming 'id' column in the table
|
|
115
|
+
const criteriaMatched = await this.filterEvaluator.evaluateCriteria(
|
|
116
|
+
mappedEntityType,
|
|
117
|
+
filter,
|
|
118
|
+
entityIdToUse,
|
|
119
|
+
jobData,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
this.logger.debug(
|
|
123
|
+
`⚖️ Criteria check for entity ${entityIdToUse} -> ${criteriaMatched}`,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
if (criteriaMatched) {
|
|
127
|
+
matchedEntities.push(record);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 🧮 Step 3: Execute workflow actions for matched entities
|
|
132
|
+
if (!matchedEntities.length) {
|
|
133
|
+
this.logger.log(`No records passed criteria for workflow ${workflowId}`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.logger.log(
|
|
138
|
+
`✅ ${matchedEntities.length} entities passed criteria, executing actions...`,
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
for (const entity of matchedEntities) {
|
|
142
|
+
await this.workflowAutomationEngineService.executeActions(
|
|
143
|
+
workflowId,
|
|
144
|
+
entity,
|
|
145
|
+
jobData,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BadRequestException,
|
|
3
|
+
Inject,
|
|
4
|
+
Injectable,
|
|
5
|
+
Logger,
|
|
6
|
+
NotFoundException,
|
|
7
|
+
} from '@nestjs/common';
|
|
2
8
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
3
9
|
import { DataSource, Repository } from 'typeorm';
|
|
4
10
|
import { WorkflowAutomation } from '../entity/workflow-automation.entity';
|
|
@@ -7,7 +13,9 @@ import { EntityServiceImpl } from 'src/module/meta/service/entity-service-impl.s
|
|
|
7
13
|
import { UserData } from 'src/module/user/entity/user.entity';
|
|
8
14
|
import { SavedFilterService } from 'src/module/filter/service/saved-filter.service';
|
|
9
15
|
import { ENTITYTYPE_SAVEDFILTERMASTER } from 'src/constant/global.constant';
|
|
10
|
-
import {
|
|
16
|
+
import { ScheduledWorkflow } from 'src/module/workflow-schedule/entities/scheduled-workflow.entity';
|
|
17
|
+
import { WorkflowScheduleService } from 'src/module/workflow-schedule/service/workflow-schedule.service';
|
|
18
|
+
import * as moment from 'moment';
|
|
11
19
|
|
|
12
20
|
@Injectable()
|
|
13
21
|
export class WorkflowAutomationService extends EntityServiceImpl {
|
|
@@ -20,6 +28,9 @@ export class WorkflowAutomationService extends EntityServiceImpl {
|
|
|
20
28
|
@Inject('SavedFilterService')
|
|
21
29
|
private readonly savedFilterService: SavedFilterService,
|
|
22
30
|
private readonly dataSource: DataSource,
|
|
31
|
+
@InjectRepository(ScheduledWorkflow)
|
|
32
|
+
private readonly scheduledWorkflowRepository: Repository<ScheduledWorkflow>,
|
|
33
|
+
private readonly workflowScheduleService: WorkflowScheduleService,
|
|
23
34
|
) {
|
|
24
35
|
super();
|
|
25
36
|
}
|
|
@@ -131,11 +142,13 @@ export class WorkflowAutomationService extends EntityServiceImpl {
|
|
|
131
142
|
if (event.triggerType === 'on_schedule') {
|
|
132
143
|
// just store JSON directly into schedule column
|
|
133
144
|
workflow.schedule = event?.scheduleJson ?? null;
|
|
145
|
+
workflow.trigger_type = 'on_schedule';
|
|
134
146
|
this.logger.log(
|
|
135
147
|
`Stored schedule JSON for workflow ${workflow.id}: ${JSON.stringify(
|
|
136
148
|
workflow.schedule,
|
|
137
149
|
)}`,
|
|
138
150
|
);
|
|
151
|
+
await this.registerScheduleAutomation(workflow, loggedInUser);
|
|
139
152
|
}
|
|
140
153
|
|
|
141
154
|
workflow.trigger_type = event.triggerType;
|
|
@@ -344,4 +357,152 @@ export class WorkflowAutomationService extends EntityServiceImpl {
|
|
|
344
357
|
this.logger.debug(`Fetched WorkflowAutomation (id=${id}) with relations`);
|
|
345
358
|
return response;
|
|
346
359
|
}
|
|
360
|
+
|
|
361
|
+
async registerScheduleAutomation(workflow: any, loggedInUser: UserData) {
|
|
362
|
+
this.logger.log(
|
|
363
|
+
`Registering schedule automation for workflow ${workflow.id}`,
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
const scheduleJson = workflow.schedule;
|
|
367
|
+
if (!scheduleJson) {
|
|
368
|
+
this.logger.warn(`No schedule JSON provided for workflow ${workflow.id}`);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Try to find an existing scheduled workflow by workflow_id
|
|
373
|
+
const existingSchedule = await this.scheduledWorkflowRepository.findOne({
|
|
374
|
+
where: { workflow_id: workflow.id },
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
const cronExpression = await this.generateDailyCron(scheduleJson.fixedTime);
|
|
378
|
+
|
|
379
|
+
const payload = {
|
|
380
|
+
workflow_id: workflow.id,
|
|
381
|
+
workflow_name: workflow.name,
|
|
382
|
+
name: scheduleJson.name ?? `Schedule_${workflow.id}`,
|
|
383
|
+
description: scheduleJson.description ?? '',
|
|
384
|
+
cron_expression: cronExpression,
|
|
385
|
+
timezone: scheduleJson.timezone ?? 'Asia/Kolkata',
|
|
386
|
+
start_date: scheduleJson.start_date ?? null,
|
|
387
|
+
end_date: scheduleJson.end_date ?? null,
|
|
388
|
+
max_executions: scheduleJson.max_executions ?? null,
|
|
389
|
+
retry_config: scheduleJson.retry_config ?? {},
|
|
390
|
+
actions: scheduleJson.actions ?? [],
|
|
391
|
+
metadata: scheduleJson.metadata ?? {},
|
|
392
|
+
is_enabled: scheduleJson.is_enabled ?? true,
|
|
393
|
+
organization_id: loggedInUser.organization_id,
|
|
394
|
+
enterprise_id: loggedInUser.enterprise_id,
|
|
395
|
+
level_id: loggedInUser.level_id,
|
|
396
|
+
level_type: loggedInUser.level_type,
|
|
397
|
+
appcode: loggedInUser.appcode,
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
if (existingSchedule) {
|
|
401
|
+
this.logger.log(
|
|
402
|
+
`Existing schedule found (id=${existingSchedule.id}), updating...`,
|
|
403
|
+
);
|
|
404
|
+
payload['id'] = existingSchedule.id;
|
|
405
|
+
// return await this.workflowScheduleService.updateSchedule(payload, loggedInUser);
|
|
406
|
+
} else {
|
|
407
|
+
this.logger.log(`No existing schedule found, creating new one...`);
|
|
408
|
+
return await this.workflowScheduleService.createSchedule(
|
|
409
|
+
payload,
|
|
410
|
+
loggedInUser,
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// CRON
|
|
416
|
+
|
|
417
|
+
async generateDailyCron(executionTime: string): Promise<string> {
|
|
418
|
+
const time = moment(executionTime, 'HH:mm');
|
|
419
|
+
|
|
420
|
+
if (!time.isValid()) {
|
|
421
|
+
throw new Error('Invalid executionTime format (expected HH:mm)');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const minute = time.minute();
|
|
425
|
+
const hour = time.hour();
|
|
426
|
+
|
|
427
|
+
// Ensure cron has 5 fields: minute hour day month weekday
|
|
428
|
+
const cron = `${minute} ${hour} * * *`;
|
|
429
|
+
|
|
430
|
+
// ✅ Validate against your regex before returning
|
|
431
|
+
const cronRegex =
|
|
432
|
+
/^(\*|([0-5]?\d)) (\*|([01]?\d|2[0-3])) (\*|([01]?\d|2\d|3[01])) (\*|([1-9]|1[0-2])) (\*|([0-6]))$/;
|
|
433
|
+
if (!cronRegex.test(cron)) {
|
|
434
|
+
throw new Error(
|
|
435
|
+
`Generated cron expression "${cron}" does not match expected format`,
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return '*/1 * * * *';
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Updates the sequence of multiple workflow automations.
|
|
443
|
+
*/
|
|
444
|
+
async updateSequence(
|
|
445
|
+
body: any[],
|
|
446
|
+
loggedInUser: any,
|
|
447
|
+
): Promise<{ updated: number; results: any[] }> {
|
|
448
|
+
if (!Array.isArray(body) || body.length === 0) {
|
|
449
|
+
throw new BadRequestException(
|
|
450
|
+
'Invalid input. Expected a non-empty array.',
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const results: {
|
|
455
|
+
id: number | string | null;
|
|
456
|
+
success: boolean;
|
|
457
|
+
result?: any;
|
|
458
|
+
error?: string;
|
|
459
|
+
}[] = [];
|
|
460
|
+
|
|
461
|
+
for (const item of body) {
|
|
462
|
+
const { id, sequence } = item;
|
|
463
|
+
|
|
464
|
+
// Validate required fields
|
|
465
|
+
if (!id || sequence === undefined || sequence === null) {
|
|
466
|
+
results.push({
|
|
467
|
+
id: id || null,
|
|
468
|
+
success: false,
|
|
469
|
+
error: 'Missing id or sequence',
|
|
470
|
+
});
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
try {
|
|
475
|
+
// Check if workflow exists
|
|
476
|
+
const existing = await this.wfRepo.findOne({ where: { id } });
|
|
477
|
+
if (!existing) {
|
|
478
|
+
results.push({
|
|
479
|
+
id,
|
|
480
|
+
success: false,
|
|
481
|
+
error: `Workflow with id ${id} not found`,
|
|
482
|
+
});
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Update sequence + audit fields
|
|
487
|
+
existing.sequence = Number(sequence);
|
|
488
|
+
existing.modified_by =
|
|
489
|
+
loggedInUser?.id || loggedInUser?.user_id || null;
|
|
490
|
+
existing.modified_date = new Date();
|
|
491
|
+
|
|
492
|
+
const saved = await this.wfRepo.save(existing);
|
|
493
|
+
results.push({ id, success: true, result: saved });
|
|
494
|
+
} catch (err) {
|
|
495
|
+
results.push({
|
|
496
|
+
id,
|
|
497
|
+
success: false,
|
|
498
|
+
error: err.message || 'Unknown error occurred',
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return {
|
|
504
|
+
updated: results.filter((r) => r.success).length,
|
|
505
|
+
results,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
347
508
|
}
|
|
@@ -9,12 +9,17 @@ import { WorkflowAutomationService } from './service/workflow-automation.service
|
|
|
9
9
|
import { WorkflowAutomationActionEntity } from './entity/workflow-automation-action.entity';
|
|
10
10
|
import { EntityModule } from '../meta/entity.module';
|
|
11
11
|
import { ActionRegistryService } from './service/action-registery.service';
|
|
12
|
+
import { ScheduleHandlerService } from './service/schedule-handler.service';
|
|
13
|
+
import { ScheduledWorkflow } from '../workflow-schedule/entities/scheduled-workflow.entity';
|
|
14
|
+
import { WorkflowExecutionLog } from '../workflow-schedule/entities/workflow-execution-log.entity';
|
|
12
15
|
|
|
13
16
|
@Module({
|
|
14
17
|
imports: [
|
|
15
18
|
TypeOrmModule.forFeature([
|
|
16
19
|
WorkflowAutomation,
|
|
17
20
|
WorkflowAutomationActionEntity,
|
|
21
|
+
ScheduledWorkflow, // 👈 Required by WorkflowAutomationService
|
|
22
|
+
WorkflowExecutionLog, // 👈 May be used by services
|
|
18
23
|
]),
|
|
19
24
|
FilterModule,
|
|
20
25
|
forwardRef(() => EntityModule),
|
|
@@ -26,9 +31,17 @@ import { ActionRegistryService } from './service/action-registery.service';
|
|
|
26
31
|
provide: 'WorkflowAutomationService',
|
|
27
32
|
useClass: WorkflowAutomationService,
|
|
28
33
|
},
|
|
34
|
+
{
|
|
35
|
+
provide: 'ScheduleHandlerService',
|
|
36
|
+
useClass: ScheduleHandlerService,
|
|
37
|
+
},
|
|
29
38
|
ActionRegistryService, // 👈 auto-registers actions
|
|
30
39
|
],
|
|
31
|
-
exports: [
|
|
40
|
+
exports: [
|
|
41
|
+
WorkflowAutomationEngineService,
|
|
42
|
+
'WorkflowAutomationService',
|
|
43
|
+
'ScheduleHandlerService',
|
|
44
|
+
],
|
|
32
45
|
controllers: [WorkflowAutomationController],
|
|
33
46
|
})
|
|
34
47
|
export class WorkflowAutomationModule {}
|