rez_core 5.0.181 → 6.5.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/.claude/settings.local.json +26 -0
- package/.idea/250218_nodejs_core.iml +8 -11
- package/.idea/codeStyles/Project.xml +58 -58
- package/.idea/codeStyles/codeStyleConfig.xml +4 -4
- package/.idea/copilot.data.migration.agent.xml +6 -0
- package/.idea/copilot.data.migration.ask.xml +6 -0
- package/.idea/copilot.data.migration.ask2agent.xml +6 -0
- package/.idea/copilot.data.migration.edit.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +1 -1
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +7 -7
- package/.idea/prettier.xml +5 -5
- package/.idea/vcs.xml +5 -5
- package/.prettierrc +3 -3
- package/README.md +99 -99
- package/dist/module/auth/guards/role.guard.js +3 -3
- package/dist/module/enterprise/controller/enterprise.controller.d.ts +12 -0
- package/dist/module/enterprise/controller/enterprise.controller.js +57 -0
- package/dist/module/enterprise/controller/enterprise.controller.js.map +1 -0
- package/dist/module/enterprise/controller/organization.controller.d.ts +11 -1
- package/dist/module/enterprise/controller/organization.controller.js +62 -2
- package/dist/module/enterprise/controller/organization.controller.js.map +1 -1
- package/dist/module/enterprise/enterprise.module.js +2 -1
- package/dist/module/enterprise/enterprise.module.js.map +1 -1
- package/dist/module/enterprise/entity/enterprise.entity.d.ts +1 -3
- package/dist/module/enterprise/entity/enterprise.entity.js +4 -12
- package/dist/module/enterprise/entity/enterprise.entity.js.map +1 -1
- package/dist/module/enterprise/entity/organization.entity.d.ts +1 -17
- package/dist/module/enterprise/entity/organization.entity.js +4 -72
- package/dist/module/enterprise/entity/organization.entity.js.map +1 -1
- package/dist/module/enterprise/repository/enterprise.repository.d.ts +2 -2
- package/dist/module/enterprise/repository/enterprise.repository.js +9 -4
- package/dist/module/enterprise/repository/enterprise.repository.js.map +1 -1
- package/dist/module/enterprise/service/enterprise.service.d.ts +2 -2
- package/dist/module/enterprise/service/enterprise.service.js +4 -4
- package/dist/module/enterprise/service/enterprise.service.js.map +1 -1
- package/dist/module/enterprise/service/organization.service.d.ts +2 -2
- package/dist/module/enterprise/service/organization.service.js +97 -20
- package/dist/module/enterprise/service/organization.service.js.map +1 -1
- package/dist/module/filter/entity/saved-filter-master.entity.d.ts +1 -0
- package/dist/module/filter/entity/saved-filter-master.entity.js +4 -0
- package/dist/module/filter/entity/saved-filter-master.entity.js.map +1 -1
- package/dist/module/filter/repository/saved-filter.repository.js +2 -0
- package/dist/module/filter/repository/saved-filter.repository.js.map +1 -1
- package/dist/module/filter/service/filter.service.js +19 -19
- package/dist/module/integration/examples/usage.example.js +9 -9
- package/dist/module/meta/repository/attribute-master.repository.js +8 -8
- package/dist/module/meta/service/entity-dynamic.service.js +16 -16
- package/dist/module/meta/service/media-data.service.js +6 -6
- package/dist/module/meta/service/resolver.service.js +11 -11
- package/dist/module/module/repository/menu.repository.js +4 -4
- package/dist/module/notification/service/notification.service.js +6 -6
- package/dist/module/user/controller/login.controller.js +18 -18
- package/dist/module/workflow/repository/action.repository.js +2 -2
- package/dist/module/workflow/repository/stage.repository.js +8 -8
- package/dist/module/workflow/service/action-template-mapping.service.js +2 -2
- package/dist/module/workflow/service/action.service.js +5 -5
- package/dist/module/workflow/service/entity-modification.service.js +2 -2
- package/dist/module/workflow/service/task.service.js +8 -8
- package/dist/module/workflow-automation/service/schedule-handler.service.js +9 -9
- package/dist/table.config.d.ts +1 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/service/reflection-helper.service.js +2 -2
- package/docs/modules/event-driven-integration-design.md +91 -91
- package/docs/modules/integration.md +250 -250
- package/eslint.config.mjs +34 -34
- package/nest-cli.json +14 -14
- package/package.json +125 -125
- package/server.log +850 -0
- package/src/app.controller.ts +12 -12
- package/src/app.module.ts +68 -68
- package/src/app.service.ts +8 -8
- package/src/config/bull.config.ts +69 -69
- package/src/config/config.module.ts +17 -17
- package/src/config/database.config.ts +48 -48
- package/src/constant/global.constant.ts +67 -67
- package/src/core.module.ts +94 -94
- package/src/decorators/roles.decorator.ts +7 -7
- package/src/dtos/response.dto.ts +6 -6
- package/src/dtos/response.ts +5 -5
- package/src/index.ts +1 -1
- package/src/module/auth/auth.module.ts +49 -49
- package/src/module/auth/controller/auth.controller.ts +28 -28
- package/src/module/auth/guards/google-auth.guard.ts +9 -9
- package/src/module/auth/guards/jwt.guard.ts +22 -22
- package/src/module/auth/guards/role.guard.ts +68 -68
- package/src/module/auth/services/auth.service.ts +56 -56
- package/src/module/auth/services/jwt.service.ts +11 -11
- package/src/module/auth/strategies/google.strategy.ts +54 -54
- package/src/module/auth/strategies/jwt.strategy.ts +58 -58
- package/src/module/auth/strategies/local.strategy.ts +13 -13
- package/src/module/dashboard/controller/dashboard.controller.ts +38 -38
- package/src/module/dashboard/dashboard.module.ts +21 -21
- package/src/module/dashboard/entity/dashboard_page_data.entity.ts +27 -27
- package/src/module/dashboard/entity/widget_master.entity.ts +18 -18
- package/src/module/dashboard/repository/dashboard.repository.ts +49 -49
- package/src/module/dashboard/service/dashboard.service.ts +72 -72
- package/src/module/enterprise/controller/enterprise.controller.ts +40 -0
- package/src/module/enterprise/controller/organization.controller.ts +93 -36
- package/src/module/enterprise/enterprise.module.ts +46 -45
- package/src/module/enterprise/entity/enterprise.entity.ts +31 -37
- package/src/module/enterprise/entity/organization-app-mapping.entity.ts +13 -13
- package/src/module/enterprise/entity/organization.entity.ts +40 -92
- package/src/module/enterprise/repository/enterprise.repository.ts +39 -31
- package/src/module/enterprise/repository/organization.repository.ts +26 -26
- package/src/module/enterprise/repository/school.repository.ts +272 -272
- package/src/module/enterprise/service/brand.service.ts +5 -5
- package/src/module/enterprise/service/enterprise.service.ts +22 -16
- package/src/module/enterprise/service/organization-app-mapping.service.ts +4 -4
- package/src/module/enterprise/service/organization.service.ts +262 -145
- package/src/module/entity_json/controller/entity_json.controller.ts +47 -47
- package/src/module/entity_json/entity/entityJson.entity.ts +39 -39
- package/src/module/entity_json/entity_json.module.ts +18 -18
- package/src/module/entity_json/service/entityJson.repository.ts +37 -37
- package/src/module/entity_json/service/entity_json.service.ts +241 -241
- package/src/module/export/controller/export.controller.ts +83 -83
- package/src/module/export/export.module.ts +14 -14
- package/src/module/export/service/export.service.ts +105 -105
- package/src/module/filter/controller/filter.controller.ts +87 -87
- package/src/module/filter/dto/filter-request.dto.ts +39 -39
- package/src/module/filter/entity/saved-filter-detail.entity.ts +41 -41
- package/src/module/filter/entity/saved-filter-master.entity.ts +35 -32
- package/src/module/filter/filter.module.ts +33 -33
- package/src/module/filter/repository/saved-filter.repository.ts +247 -258
- package/src/module/filter/repository/saved.filter-detail.repository.ts +19 -19
- package/src/module/filter/service/filter-evaluator.service.ts +82 -82
- package/src/module/filter/service/filter.service.ts +1316 -1316
- package/src/module/filter/service/saved-filter.service.ts +164 -164
- package/src/module/ics/controller/ics.controller.ts +21 -21
- package/src/module/ics/dto/ics.dto.ts +55 -55
- package/src/module/ics/ics.module.ts +13 -13
- package/src/module/ics/service/ics.service.ts +57 -57
- package/src/module/integration/controller/calender-event.controller.ts +31 -31
- package/src/module/integration/controller/integration.controller.ts +662 -662
- package/src/module/integration/controller/wrapper.controller.ts +37 -37
- package/src/module/integration/dto/create-config.dto.ts +526 -526
- package/src/module/integration/entity/integration-config.entity.ts +112 -112
- package/src/module/integration/entity/integration-entity-mapper.entity.ts +14 -14
- package/src/module/integration/entity/integration-source.entity.ts +17 -17
- package/src/module/integration/entity/user-integration.entity.ts +71 -71
- package/src/module/integration/examples/usage.example.ts +338 -338
- package/src/module/integration/factories/base.factory.ts +7 -7
- package/src/module/integration/factories/email.factory.ts +49 -49
- package/src/module/integration/factories/integration.factory.ts +121 -121
- package/src/module/integration/factories/sms.factory.ts +51 -51
- package/src/module/integration/factories/telephone.factory.ts +41 -41
- package/src/module/integration/factories/whatsapp.factory.ts +56 -56
- package/src/module/integration/integration.module.ts +110 -110
- package/src/module/integration/service/calendar-event.service.ts +118 -118
- package/src/module/integration/service/integration-entity-mapper.service.ts +17 -17
- package/src/module/integration/service/integration-queue.service.ts +229 -229
- package/src/module/integration/service/integration.service.ts +2634 -2634
- package/src/module/integration/service/oauth.service.ts +224 -224
- package/src/module/integration/service/wrapper.service.ts +753 -753
- package/src/module/integration/strategies/email/gmail-api.strategy.ts +280 -280
- package/src/module/integration/strategies/email/outlook-api.strategy.ts +44 -44
- package/src/module/integration/strategies/email/outlook.strategy.ts +64 -64
- package/src/module/integration/strategies/email/sendgrid-api.strategy.ts +260 -260
- package/src/module/integration/strategies/integration.strategy.ts +97 -97
- package/src/module/integration/strategies/sms/gupshup-sms.strategy.ts +146 -146
- package/src/module/integration/strategies/sms/msg91-sms.strategy.ts +164 -164
- package/src/module/integration/strategies/sms/tubelight-sms.strategy.ts +163 -163
- package/src/module/integration/strategies/telephone/ozonetel-voice.strategy.ts +238 -238
- package/src/module/integration/strategies/telephone/tubelight-voice.strategy.ts +210 -210
- package/src/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.ts +359 -359
- package/src/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.ts +372 -372
- package/src/module/integration/strategies/whatsapp/whatsapp-cloud.strategy.ts +403 -403
- package/src/module/integration/strategies/whatsapp/whatsapp.strategy.ts +57 -57
- package/src/module/layout/controller/layout.controller.ts +47 -47
- package/src/module/layout/entity/header-items.entity.ts +28 -28
- package/src/module/layout/entity/header-section.entity.ts +19 -19
- package/src/module/layout/layout.module.ts +21 -21
- package/src/module/layout/repository/header-items.repository.ts +18 -18
- package/src/module/layout/repository/header-section.repository.ts +22 -22
- package/src/module/layout/service/header-section.service.ts +25 -25
- package/src/module/layout_preference/controller/layout_preference.controller.ts +76 -76
- package/src/module/layout_preference/entity/layout_preference.entity.ts +28 -28
- package/src/module/layout_preference/layout_preference.module.ts +22 -22
- package/src/module/layout_preference/repository/layout_preference.repository.ts +65 -65
- package/src/module/layout_preference/service/layout_preference.service.ts +191 -191
- package/src/module/lead/controller/lead.controller.ts +30 -30
- package/src/module/lead/lead.module.ts +14 -14
- package/src/module/lead/repository/lead.repository.ts +41 -41
- package/src/module/lead/service/lead.service.ts +54 -54
- package/src/module/linked_attributes/controller/linked_attributes.controller.ts +37 -37
- package/src/module/linked_attributes/entity/linked_attribute.entity.ts +51 -51
- package/src/module/linked_attributes/linked_attributes.module.ts +16 -16
- package/src/module/linked_attributes/repository/linked_attribute.repository.ts +12 -12
- package/src/module/linked_attributes/service/linked_attributes.service.ts +73 -73
- package/src/module/listmaster/controller/list-master.controller.ts +230 -230
- package/src/module/listmaster/entity/list-master-items.entity.ts +43 -43
- package/src/module/listmaster/entity/list-master.entity.ts +33 -33
- package/src/module/listmaster/listmaster.module.ts +46 -46
- package/src/module/listmaster/repository/list-master-items.repository.ts +173 -173
- package/src/module/listmaster/repository/list-master.repository.ts +56 -56
- package/src/module/listmaster/service/list-master-engine.ts +19 -19
- package/src/module/listmaster/service/list-master-extension.interface.ts +4 -4
- package/src/module/listmaster/service/list-master-item.service.ts +280 -280
- package/src/module/listmaster/service/list-master-registry.ts +15 -15
- package/src/module/listmaster/service/list-master.service.ts +527 -527
- package/src/module/mapper/controller/field-mapper.controller.ts +76 -76
- package/src/module/mapper/controller/mapper.controller.ts +20 -20
- package/src/module/mapper/dto/field-mapper.dto.ts +14 -14
- package/src/module/mapper/entity/field-lovs.entity.ts +19 -19
- package/src/module/mapper/entity/field-mapper.entity.ts +53 -53
- package/src/module/mapper/entity/mapper.entity.ts +16 -16
- package/src/module/mapper/mapper.module.ts +35 -35
- package/src/module/mapper/repository/field-lovs.repository.ts +35 -35
- package/src/module/mapper/repository/field-mapper.repository.ts +42 -42
- package/src/module/mapper/repository/mapper.repository.ts +32 -32
- package/src/module/mapper/service/field-mapper.service.ts +269 -269
- package/src/module/mapper/service/mapper.service.ts +80 -80
- package/src/module/master/controller/master.controller.ts +74 -74
- package/src/module/master/service/master.service.ts +484 -484
- package/src/module/meta/controller/app-master.controller.ts +38 -38
- package/src/module/meta/controller/attribute-master.controller.ts +84 -84
- package/src/module/meta/controller/entity-dynamic.controller.ts +125 -125
- package/src/module/meta/controller/entity-master.controller.ts +41 -41
- package/src/module/meta/controller/entity-relation.controller.ts +36 -36
- package/src/module/meta/controller/entity.controller.ts +308 -308
- package/src/module/meta/controller/entity.public.controller.ts +75 -75
- package/src/module/meta/controller/media.controller.ts +135 -135
- package/src/module/meta/controller/meta.controller.ts +101 -101
- package/src/module/meta/controller/view-master.controller.ts +79 -79
- package/src/module/meta/dto/entity-list-data.dto.ts +6 -6
- package/src/module/meta/dto/entity-tab.dto.ts +4 -4
- package/src/module/meta/dto/entity-table.dto.ts +12 -12
- package/src/module/meta/entity/app-master.entity.ts +37 -37
- package/src/module/meta/entity/attribute-master.entity.ts +92 -92
- package/src/module/meta/entity/base-entity.entity.ts +75 -75
- package/src/module/meta/entity/entity-master.entity.ts +85 -85
- package/src/module/meta/entity/entity-relation-data.entity.ts +29 -29
- package/src/module/meta/entity/entity-relation.entity.ts +23 -23
- package/src/module/meta/entity/entity-table-column.entity.ts +61 -61
- package/src/module/meta/entity/entity-table.entity.ts +50 -50
- package/src/module/meta/entity/media-data.entity.ts +32 -32
- package/src/module/meta/entity/preference.entity.ts +62 -62
- package/src/module/meta/entity/view-master.entity.ts +41 -41
- package/src/module/meta/entity.module.ts +165 -165
- package/src/module/meta/repository/app-master.repository.ts +20 -20
- package/src/module/meta/repository/attribute-master.repository.ts +164 -164
- package/src/module/meta/repository/entity-attribute-update.repository.ts +48 -48
- package/src/module/meta/repository/entity-master.repository.ts +120 -120
- package/src/module/meta/repository/entity-relation.repository.ts +22 -22
- package/src/module/meta/repository/entity-table-column.repository.ts +39 -39
- package/src/module/meta/repository/entity-table.repository.ts +53 -53
- package/src/module/meta/repository/media-data.repository.ts +50 -50
- package/src/module/meta/repository/preference.repository.ts +20 -20
- package/src/module/meta/repository/user-app-mapping.repository.ts +28 -28
- package/src/module/meta/repository/view-master.repository.ts +42 -42
- package/src/module/meta/service/app-master.service.ts +37 -37
- package/src/module/meta/service/attribute-master.service.ts +132 -132
- package/src/module/meta/service/common.service.ts +9 -9
- package/src/module/meta/service/entity-attribute-update.service.ts +26 -26
- package/src/module/meta/service/entity-dynamic.service.ts +824 -824
- package/src/module/meta/service/entity-master.service.ts +171 -171
- package/src/module/meta/service/entity-realation-data.service.ts +9 -9
- package/src/module/meta/service/entity-relation.service.ts +74 -74
- package/src/module/meta/service/entity-service-impl.service.ts +388 -388
- package/src/module/meta/service/entity-table-column.service.ts +26 -26
- package/src/module/meta/service/entity-table.service.ts +157 -157
- package/src/module/meta/service/entity-validation.service.ts +188 -188
- package/src/module/meta/service/entity.service.ts +49 -49
- package/src/module/meta/service/field-group.service.ts +103 -103
- package/src/module/meta/service/media-data.service.ts +591 -591
- package/src/module/meta/service/populate-meta.service.ts +222 -222
- package/src/module/meta/service/preference.service.ts +16 -16
- package/src/module/meta/service/resolver.service.ts +280 -280
- package/src/module/meta/service/section-master.service.ts +104 -104
- package/src/module/meta/service/update-form-json.service.ts +22 -22
- package/src/module/meta/service/user-app-mapping.service.ts +17 -17
- package/src/module/meta/service/view-master.service.ts +127 -127
- package/src/module/microservice-client/microservice-clients.module.ts +13 -13
- package/src/module/microservice-client/service/microservice-client-factory.ts +37 -37
- package/src/module/microservice-client/service/microservice-clients.ts +4 -4
- package/src/module/module/controller/menu.controller.ts +15 -15
- package/src/module/module/controller/module-access.controller.ts +133 -133
- package/src/module/module/entity/menu.entity.ts +43 -43
- package/src/module/module/entity/module-access.entity.ts +25 -25
- package/src/module/module/entity/module-action.entity.ts +17 -17
- package/src/module/module/entity/module.entity.ts +52 -52
- package/src/module/module/module.module.ts +42 -42
- package/src/module/module/repository/menu.repository.ts +186 -186
- package/src/module/module/repository/module-access.repository.ts +344 -344
- package/src/module/module/service/menu.service.ts +82 -82
- package/src/module/module/service/module-access.service.ts +189 -189
- package/src/module/notification/controller/notification.controller.ts +58 -58
- package/src/module/notification/controller/otp.controller.ts +117 -117
- package/src/module/notification/entity/notification.entity.ts +26 -26
- package/src/module/notification/entity/otp.entity.ts +28 -28
- package/src/module/notification/firebase-admin.config.ts +22 -22
- package/src/module/notification/notification.module.ts +69 -69
- package/src/module/notification/repository/otp.repository.ts +27 -27
- package/src/module/notification/service/email.service.ts +127 -127
- package/src/module/notification/service/notification.service.ts +164 -164
- package/src/module/notification/service/otp.service.ts +133 -133
- package/src/module/third-party-module/entity/third-party-api-registry.entity.ts +52 -52
- package/src/module/third-party-module/repository/third-party-api-registry.repository.ts +20 -20
- package/src/module/third-party-module/service/api-registry.service.ts +13 -13
- package/src/module/third-party-module/third-party.module.ts +12 -12
- package/src/module/user/controller/login.controller.ts +198 -198
- package/src/module/user/controller/user.controller.ts +40 -40
- package/src/module/user/dto/create-user.dto.ts +62 -62
- package/src/module/user/dto/update-user.dto.ts +4 -4
- package/src/module/user/entity/role.entity.ts +33 -33
- package/src/module/user/entity/user-role-mapping.entity.ts +38 -38
- package/src/module/user/entity/user-session.entity.ts +73 -73
- package/src/module/user/entity/user.entity.ts +62 -62
- package/src/module/user/repository/role.repository.ts +96 -96
- package/src/module/user/repository/user-role-mapping.repository.ts +126 -126
- package/src/module/user/repository/user.repository.ts +50 -50
- package/src/module/user/repository/userSession.repository.ts +33 -33
- package/src/module/user/service/login.service.ts +326 -326
- package/src/module/user/service/role.service.ts +197 -197
- package/src/module/user/service/user-role-mapping.service.ts +98 -98
- package/src/module/user/service/user-session.service.ts +200 -200
- package/src/module/user/service/user.service.ts +368 -368
- package/src/module/user/user.module.ts +65 -65
- package/src/module/workflow/controller/action-category.controller.ts +54 -54
- package/src/module/workflow/controller/action-resource-mapping.controller.ts +23 -23
- package/src/module/workflow/controller/action-template-mapping.controller.ts +35 -35
- package/src/module/workflow/controller/action.controller.ts +111 -111
- package/src/module/workflow/controller/activity-log.controller.ts +55 -55
- package/src/module/workflow/controller/comm-template.controller.ts +43 -43
- package/src/module/workflow/controller/entity-modification.controller.ts +35 -35
- package/src/module/workflow/controller/form-master.controller.ts +43 -43
- package/src/module/workflow/controller/stage-group.controller.ts +49 -49
- package/src/module/workflow/controller/stage.controller.ts +51 -51
- package/src/module/workflow/controller/task.controller.ts +77 -77
- package/src/module/workflow/controller/workflow-list-master.controller.ts +44 -44
- package/src/module/workflow/controller/workflow-meta.controller.ts +80 -80
- package/src/module/workflow/controller/workflow.controller.ts +67 -67
- package/src/module/workflow/entity/action-category.entity.ts +38 -38
- package/src/module/workflow/entity/action-data.entity.ts +55 -55
- package/src/module/workflow/entity/action-resources-mapping.entity.ts +29 -29
- package/src/module/workflow/entity/action-template-mapping.entity.ts +17 -17
- package/src/module/workflow/entity/action.entity.ts +53 -53
- package/src/module/workflow/entity/activity-log.entity.ts +43 -43
- package/src/module/workflow/entity/comm-template.entity.ts +43 -43
- package/src/module/workflow/entity/entity-modification.entity.ts +38 -38
- package/src/module/workflow/entity/form.entity.ts +25 -25
- package/src/module/workflow/entity/stage-action-mapping.entity.ts +17 -17
- package/src/module/workflow/entity/stage-group.entity.ts +23 -23
- package/src/module/workflow/entity/stage-movement-data.entity.ts +38 -38
- package/src/module/workflow/entity/stage.entity.ts +20 -20
- package/src/module/workflow/entity/task-data.entity.ts +88 -88
- package/src/module/workflow/entity/template-attach-mapper.entity.ts +30 -30
- package/src/module/workflow/entity/workflow-data.entity.ts +11 -11
- package/src/module/workflow/entity/workflow-level-mapping.entity.ts +18 -18
- package/src/module/workflow/entity/workflow.entity.ts +20 -20
- package/src/module/workflow/repository/action-category.repository.ts +79 -79
- package/src/module/workflow/repository/action-data.repository.ts +347 -347
- package/src/module/workflow/repository/action.repository.ts +339 -339
- package/src/module/workflow/repository/activity-log.repository.ts +148 -148
- package/src/module/workflow/repository/comm-template.repository.ts +157 -157
- package/src/module/workflow/repository/form-master.repository.ts +50 -50
- package/src/module/workflow/repository/stage-group.repository.ts +186 -186
- package/src/module/workflow/repository/stage-movement.repository.ts +217 -217
- package/src/module/workflow/repository/stage.repository.ts +160 -160
- package/src/module/workflow/repository/task.repository.ts +154 -154
- package/src/module/workflow/repository/workflow.repository.ts +42 -42
- package/src/module/workflow/service/action-category.service.ts +33 -33
- package/src/module/workflow/service/action-data.service.ts +62 -62
- package/src/module/workflow/service/action-resources-mapping.service.ts +10 -10
- package/src/module/workflow/service/action-template-mapping.service.ts +137 -137
- package/src/module/workflow/service/action.service.ts +302 -302
- package/src/module/workflow/service/activity-log.service.ts +107 -107
- package/src/module/workflow/service/comm-template.service.ts +181 -181
- package/src/module/workflow/service/entity-modification.service.ts +61 -61
- package/src/module/workflow/service/form-master.service.ts +35 -35
- package/src/module/workflow/service/populate-workflow.service.ts +320 -320
- package/src/module/workflow/service/stage-action-mapping.service.ts +5 -5
- package/src/module/workflow/service/stage-group.service.ts +325 -325
- package/src/module/workflow/service/stage.service.ts +197 -197
- package/src/module/workflow/service/task.service.ts +551 -551
- package/src/module/workflow/service/workflow-list-master.service.ts +68 -68
- package/src/module/workflow/service/workflow-meta.service.ts +640 -640
- package/src/module/workflow/service/workflow.service.ts +213 -213
- package/src/module/workflow/workflow.module.ts +180 -180
- package/src/module/workflow-automation/SCHEDULING_GUIDE.md +145 -145
- package/src/module/workflow-automation/controller/workflow-automation.controller.ts +43 -43
- package/src/module/workflow-automation/entity/workflow-automation-action.entity.ts +26 -26
- package/src/module/workflow-automation/entity/workflow-automation.entity.ts +40 -40
- package/src/module/workflow-automation/interface/action.decorator.ts +7 -7
- package/src/module/workflow-automation/interface/action.interface.ts +5 -5
- package/src/module/workflow-automation/service/action-registery.service.ts +35 -35
- package/src/module/workflow-automation/service/schedule-handler.service.ts +168 -168
- package/src/module/workflow-automation/service/workflow-automation-engine.service.ts +219 -219
- package/src/module/workflow-automation/service/workflow-automation.service.ts +476 -476
- package/src/module/workflow-automation/workflow-automation.module.ts +54 -54
- package/src/module/workflow-schedule/INSTALLATION.md +244 -244
- package/src/module/workflow-schedule/MULTI_PROJECT_GUIDE.md +196 -196
- package/src/module/workflow-schedule/README.md +422 -422
- package/src/module/workflow-schedule/constants/schedule.constants.ts +48 -48
- package/src/module/workflow-schedule/controller/workflow-schedule.controller.ts +253 -253
- package/src/module/workflow-schedule/docs/CLAUDE_CODE_GUIDE.md +510 -510
- package/src/module/workflow-schedule/docs/CLAUDE_CODE_PROMPT.md +362 -362
- package/src/module/workflow-schedule/docs/RUN_CLAUDE_CODE.sh +68 -68
- package/src/module/workflow-schedule/dto/create-schedule.dto.ts +147 -147
- package/src/module/workflow-schedule/dto/get-execution-logs.dto.ts +119 -119
- package/src/module/workflow-schedule/dto/update-schedule.dto.ts +96 -96
- package/src/module/workflow-schedule/entities/scheduled-workflow.entity.ts +148 -148
- package/src/module/workflow-schedule/entities/workflow-execution-log.entity.ts +154 -154
- package/src/module/workflow-schedule/interfaces/schedule-job-data.interface.ts +53 -53
- package/src/module/workflow-schedule/interfaces/workflow-schedule-options.interface.ts +12 -12
- package/src/module/workflow-schedule/processors/schedule.processor.ts +620 -620
- package/src/module/workflow-schedule/service/workflow-schedule.service.ts +597 -597
- package/src/module/workflow-schedule/workflow-schedule.module.ts +67 -67
- package/src/resources/dev.properties.yaml +31 -31
- package/src/resources/local.properties.yaml +27 -27
- package/src/resources/properties.module.ts +12 -12
- package/src/resources/properties.yaml.ts +11 -11
- package/src/resources/uat.properties.yaml +31 -31
- package/src/table.config.ts +133 -133
- package/src/utils/dto/excel-data.dto.ts +14 -14
- package/src/utils/dto/excelsheet-data.dto.ts +5 -5
- package/src/utils/service/base64util.service.ts +18 -18
- package/src/utils/service/clockIDGenUtil.service.ts +21 -21
- package/src/utils/service/codeGenerator.service.ts +22 -22
- package/src/utils/service/dateUtil.service.ts +17 -17
- package/src/utils/service/encryptUtil.service.ts +97 -97
- package/src/utils/service/excel-helper.service.ts +72 -72
- package/src/utils/service/excelUtil.service.ts +15 -15
- package/src/utils/service/file-util.service.ts +11 -11
- package/src/utils/service/json-util.service.ts +23 -23
- package/src/utils/service/loggingUtil.service.ts +88 -88
- package/src/utils/service/reflection-helper.service.ts +62 -62
- package/src/utils/service/wbsCodeGen.service.ts +8 -8
- package/src/utils/utils.module.ts +27 -27
- package/tsconfig.build.json +4 -4
- package/tsconfig.json +24 -24
|
@@ -1,620 +1,620 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Process,
|
|
3
|
-
Processor,
|
|
4
|
-
OnQueueActive,
|
|
5
|
-
OnQueueCompleted,
|
|
6
|
-
OnQueueFailed,
|
|
7
|
-
} from '@nestjs/bull';
|
|
8
|
-
import { Logger, Inject } from '@nestjs/common';
|
|
9
|
-
import { Job } from 'bull';
|
|
10
|
-
import { InjectRepository } from '@nestjs/typeorm';
|
|
11
|
-
import { Repository, DataSource } from 'typeorm';
|
|
12
|
-
import { ScheduledWorkflow } from '../entities/scheduled-workflow.entity';
|
|
13
|
-
import { WorkflowExecutionLog } from '../entities/workflow-execution-log.entity';
|
|
14
|
-
import {
|
|
15
|
-
WORKFLOW_SCHEDULE_QUEUE,
|
|
16
|
-
EXECUTE_SCHEDULED_WORKFLOW_JOB,
|
|
17
|
-
EXECUTION_STATUS_PENDING,
|
|
18
|
-
EXECUTION_STATUS_RUNNING,
|
|
19
|
-
EXECUTION_STATUS_COMPLETED,
|
|
20
|
-
EXECUTION_STATUS_FAILED,
|
|
21
|
-
EXECUTION_STATUS_PARTIAL,
|
|
22
|
-
DEFAULT_BATCH_SIZE,
|
|
23
|
-
} from '../constants/schedule.constants';
|
|
24
|
-
import {
|
|
25
|
-
ScheduleJobData,
|
|
26
|
-
BatchProcessingResult,
|
|
27
|
-
} from '../interfaces/schedule-job-data.interface';
|
|
28
|
-
import { ScheduleHandlerService } from 'src/module/workflow-automation/service/schedule-handler.service';
|
|
29
|
-
import { ReflectionHelper } from 'src/utils/service/reflection-helper.service';
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Schedule Processor
|
|
33
|
-
* Processes scheduled workflow execution jobs from Bull queue
|
|
34
|
-
*/
|
|
35
|
-
@Processor(WORKFLOW_SCHEDULE_QUEUE)
|
|
36
|
-
export class ScheduleProcessor {
|
|
37
|
-
private readonly logger = new Logger(ScheduleProcessor.name);
|
|
38
|
-
|
|
39
|
-
constructor(
|
|
40
|
-
@InjectRepository(ScheduledWorkflow)
|
|
41
|
-
private readonly scheduledWorkflowRepository: Repository<ScheduledWorkflow>,
|
|
42
|
-
@InjectRepository(WorkflowExecutionLog)
|
|
43
|
-
private readonly executionLogRepository: Repository<WorkflowExecutionLog>,
|
|
44
|
-
@Inject('ScheduleHandlerService')
|
|
45
|
-
private readonly scheduleHandlerService: ScheduleHandlerService,
|
|
46
|
-
private readonly reflectionHelper: ReflectionHelper,
|
|
47
|
-
private readonly dataSource: DataSource
|
|
48
|
-
) {}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Main job processor for scheduled workflow execution
|
|
52
|
-
*/
|
|
53
|
-
@Process(EXECUTE_SCHEDULED_WORKFLOW_JOB)
|
|
54
|
-
async handleScheduledWorkflowExecution(job: Job<ScheduleJobData>) {
|
|
55
|
-
const { scheduleId, workflowId, organizationId, triggeredBy, createdBy } =
|
|
56
|
-
job.data;
|
|
57
|
-
|
|
58
|
-
this.logger.log(
|
|
59
|
-
`🚀 [handleScheduledWorkflowExecution] Invoked for scheduleId=${scheduleId}, workflowId=${workflowId}`,
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
// Create execution log entry
|
|
63
|
-
const executionLog = this.executionLogRepository.create({
|
|
64
|
-
schedule_id: scheduleId,
|
|
65
|
-
workflow_id: workflowId,
|
|
66
|
-
job_id: job.id.toString(),
|
|
67
|
-
execution_status: EXECUTION_STATUS_PENDING,
|
|
68
|
-
triggered_by: triggeredBy,
|
|
69
|
-
triggered_by_user_id: triggeredBy === 'MANUAL' ? createdBy : null,
|
|
70
|
-
organization_id: organizationId,
|
|
71
|
-
enterprise_id: job.data.enterpriseId,
|
|
72
|
-
created_by: createdBy,
|
|
73
|
-
entity_type: 'WFEL',
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
this.logger.debug(`🧾 Creating execution log for jobId=${job.id}`);
|
|
77
|
-
await this.executionLogRepository.save(executionLog);
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
// Update status to running
|
|
81
|
-
executionLog.execution_status = EXECUTION_STATUS_RUNNING;
|
|
82
|
-
executionLog.started_at = new Date();
|
|
83
|
-
await this.executionLogRepository.save(executionLog);
|
|
84
|
-
|
|
85
|
-
this.logger.log(
|
|
86
|
-
`🏃 Workflow execution started for scheduleId=${scheduleId}`,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
// Get scheduled workflow details
|
|
90
|
-
const schedule = await this.scheduledWorkflowRepository.findOne({
|
|
91
|
-
where: { id: scheduleId },
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
if (!schedule) {
|
|
95
|
-
throw new Error(`Scheduled workflow not found: ${scheduleId}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
this.logger.debug(
|
|
99
|
-
`📋 Loaded schedule from DB: ${JSON.stringify(schedule)}`,
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
// Execute workflow actions
|
|
103
|
-
this.logger.log(`⚙️ Executing workflow actions...`);
|
|
104
|
-
const result = await this.executeWorkflowActions(schedule, job.data);
|
|
105
|
-
this.logger.debug(`🧮 Execution result: ${JSON.stringify(result)}`);
|
|
106
|
-
|
|
107
|
-
// Update execution log with results
|
|
108
|
-
const completedAt = new Date();
|
|
109
|
-
executionLog.execution_status =
|
|
110
|
-
result.failedRecords > 0 && result.successfulRecords > 0
|
|
111
|
-
? EXECUTION_STATUS_PARTIAL
|
|
112
|
-
: result.failedRecords > 0
|
|
113
|
-
? EXECUTION_STATUS_FAILED
|
|
114
|
-
: EXECUTION_STATUS_COMPLETED;
|
|
115
|
-
executionLog.completed_at = completedAt;
|
|
116
|
-
executionLog.duration_ms =
|
|
117
|
-
completedAt.getTime() - executionLog.started_at.getTime();
|
|
118
|
-
executionLog.total_records = result.totalRecords;
|
|
119
|
-
executionLog.successful_records = result.successfulRecords;
|
|
120
|
-
executionLog.failed_records = result.failedRecords;
|
|
121
|
-
executionLog.execution_details = {
|
|
122
|
-
batchesProcessed: Math.ceil(result.totalRecords / DEFAULT_BATCH_SIZE),
|
|
123
|
-
errors: result.errors,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
await this.executionLogRepository.save(executionLog);
|
|
127
|
-
|
|
128
|
-
// Update schedule execution count and last execution time
|
|
129
|
-
schedule.execution_count += 1;
|
|
130
|
-
schedule.last_execution_at = completedAt;
|
|
131
|
-
await this.scheduledWorkflowRepository.save(schedule);
|
|
132
|
-
|
|
133
|
-
this.logger.log(
|
|
134
|
-
`✅ Workflow execution completed: scheduleId=${scheduleId}, status=${executionLog.execution_status}, processed=${result.totalRecords}`,
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
success: true,
|
|
139
|
-
executionLogId: executionLog.id,
|
|
140
|
-
result,
|
|
141
|
-
};
|
|
142
|
-
} catch (error) {
|
|
143
|
-
this.logger.error(
|
|
144
|
-
`🔥 Workflow execution failed: scheduleId=${scheduleId}, error=${error.message}`,
|
|
145
|
-
error.stack,
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
// Update execution log with error
|
|
149
|
-
executionLog.execution_status = EXECUTION_STATUS_FAILED;
|
|
150
|
-
executionLog.completed_at = new Date();
|
|
151
|
-
executionLog.duration_ms = executionLog.started_at
|
|
152
|
-
? executionLog.completed_at.getTime() -
|
|
153
|
-
executionLog.started_at.getTime()
|
|
154
|
-
: 0;
|
|
155
|
-
executionLog.error_message = error.message;
|
|
156
|
-
executionLog.error_stack = error.stack;
|
|
157
|
-
|
|
158
|
-
await this.executionLogRepository.save(executionLog);
|
|
159
|
-
|
|
160
|
-
throw error;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Execute all actions defined in the workflow
|
|
166
|
-
*/
|
|
167
|
-
private async executeWorkflowActions(
|
|
168
|
-
schedule: ScheduledWorkflow,
|
|
169
|
-
jobData: ScheduleJobData,
|
|
170
|
-
): Promise<BatchProcessingResult> {
|
|
171
|
-
const result: BatchProcessingResult = {
|
|
172
|
-
totalRecords: 0,
|
|
173
|
-
processedRecords: 0,
|
|
174
|
-
successfulRecords: 0,
|
|
175
|
-
failedRecords: 0,
|
|
176
|
-
errors: [],
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const resultData: any =
|
|
180
|
-
await this.scheduleHandlerService.handleScheduledWorkflow(
|
|
181
|
-
jobData.workflowId,
|
|
182
|
-
jobData,
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
if (!schedule.actions || schedule.actions.length === 0) {
|
|
186
|
-
this.logger.warn(`No actions defined for schedule: ${schedule.id}`);
|
|
187
|
-
return result;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Execute each action sequentially
|
|
191
|
-
for (const action of schedule.actions) {
|
|
192
|
-
try {
|
|
193
|
-
const actionResult = await this.executeAction(action, jobData);
|
|
194
|
-
result.totalRecords += actionResult.totalRecords;
|
|
195
|
-
result.processedRecords += actionResult.processedRecords;
|
|
196
|
-
result.successfulRecords += actionResult.successfulRecords;
|
|
197
|
-
result.failedRecords += actionResult.failedRecords;
|
|
198
|
-
result.errors.push(...actionResult.errors);
|
|
199
|
-
} catch (error) {
|
|
200
|
-
this.logger.error(
|
|
201
|
-
`Action execution failed: actionType=${action.actionType}, error=${error.message}`,
|
|
202
|
-
);
|
|
203
|
-
result.failedRecords += 1;
|
|
204
|
-
result.errors.push({
|
|
205
|
-
error: `Action ${action.actionType} failed: ${error.message}`,
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return resultData;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Execute a single workflow action
|
|
215
|
-
*/
|
|
216
|
-
private async executeAction(action: any, jobData: ScheduleJobData) {
|
|
217
|
-
this.logger.log(`🚀 Executing scheduled action: ${action.actionType}`);
|
|
218
|
-
|
|
219
|
-
try {
|
|
220
|
-
// We’ll assume jobData contains workflowId and user info
|
|
221
|
-
const { workflowId, loggedInUser } = jobData;
|
|
222
|
-
|
|
223
|
-
// 🧠 Call your handler that performs filtering and workflow execution
|
|
224
|
-
const result: any =
|
|
225
|
-
await this.scheduleHandlerService.handleScheduledWorkflow(
|
|
226
|
-
workflowId,
|
|
227
|
-
loggedInUser,
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
this.logger.log(
|
|
231
|
-
`✅ Scheduled workflow ${workflowId} executed successfully`,
|
|
232
|
-
);
|
|
233
|
-
return {
|
|
234
|
-
totalRecords: result?.length || 0,
|
|
235
|
-
processedRecords: result?.length || 0,
|
|
236
|
-
successfulRecords: result?.length || 0,
|
|
237
|
-
failedRecords: 0,
|
|
238
|
-
errors: [],
|
|
239
|
-
};
|
|
240
|
-
} catch (error) {
|
|
241
|
-
this.logger.error(
|
|
242
|
-
`🔥 Error executing scheduled workflow action: ${error.message}`,
|
|
243
|
-
error.stack,
|
|
244
|
-
);
|
|
245
|
-
return {
|
|
246
|
-
totalRecords: 0,
|
|
247
|
-
processedRecords: 0,
|
|
248
|
-
successfulRecords: 0,
|
|
249
|
-
failedRecords: 1,
|
|
250
|
-
errors: [{ error: error.message }],
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Execute send email action
|
|
257
|
-
*/
|
|
258
|
-
private async executeSendEmailAction(
|
|
259
|
-
action: any,
|
|
260
|
-
jobData: ScheduleJobData,
|
|
261
|
-
): Promise<BatchProcessingResult> {
|
|
262
|
-
const result: BatchProcessingResult = {
|
|
263
|
-
totalRecords: 0,
|
|
264
|
-
processedRecords: 0,
|
|
265
|
-
successfulRecords: 0,
|
|
266
|
-
failedRecords: 0,
|
|
267
|
-
errors: [],
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
try {
|
|
271
|
-
// Get target records based on filter criteria
|
|
272
|
-
const records = await this.getTargetRecords(
|
|
273
|
-
action.targetEntityType,
|
|
274
|
-
action.filterCriteria,
|
|
275
|
-
jobData,
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
result.totalRecords = records.length;
|
|
279
|
-
|
|
280
|
-
// Process in batches
|
|
281
|
-
const batches = this.chunkArray(records, DEFAULT_BATCH_SIZE);
|
|
282
|
-
|
|
283
|
-
for (const batch of batches) {
|
|
284
|
-
for (const record of batch) {
|
|
285
|
-
try {
|
|
286
|
-
// TODO: Integrate with email service
|
|
287
|
-
// await this.emailService.sendEmail({
|
|
288
|
-
// to: record.email,
|
|
289
|
-
// subject: action.actionConfig.subject,
|
|
290
|
-
// template: action.actionConfig.template,
|
|
291
|
-
// data: record,
|
|
292
|
-
// });
|
|
293
|
-
|
|
294
|
-
result.processedRecords += 1;
|
|
295
|
-
result.successfulRecords += 1;
|
|
296
|
-
} catch (error) {
|
|
297
|
-
result.processedRecords += 1;
|
|
298
|
-
result.failedRecords += 1;
|
|
299
|
-
result.errors.push({
|
|
300
|
-
recordId: record.id,
|
|
301
|
-
error: error.message,
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
} catch (error) {
|
|
307
|
-
throw new Error(`Send email action failed: ${error.message}`);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return result;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Execute update records action
|
|
315
|
-
*/
|
|
316
|
-
private async executeUpdateRecordsAction(
|
|
317
|
-
action: any,
|
|
318
|
-
jobData: ScheduleJobData,
|
|
319
|
-
): Promise<BatchProcessingResult> {
|
|
320
|
-
const result: BatchProcessingResult = {
|
|
321
|
-
totalRecords: 0,
|
|
322
|
-
processedRecords: 0,
|
|
323
|
-
successfulRecords: 0,
|
|
324
|
-
failedRecords: 0,
|
|
325
|
-
errors: [],
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
try {
|
|
329
|
-
// Get target records
|
|
330
|
-
const records = await this.getTargetRecords(
|
|
331
|
-
action.targetEntityType,
|
|
332
|
-
action.filterCriteria,
|
|
333
|
-
jobData,
|
|
334
|
-
);
|
|
335
|
-
|
|
336
|
-
result.totalRecords = records.length;
|
|
337
|
-
|
|
338
|
-
// Process in batches
|
|
339
|
-
const batches = this.chunkArray(records, DEFAULT_BATCH_SIZE);
|
|
340
|
-
|
|
341
|
-
for (const batch of batches) {
|
|
342
|
-
const queryRunner = this.dataSource.createQueryRunner();
|
|
343
|
-
await queryRunner.connect();
|
|
344
|
-
await queryRunner.startTransaction();
|
|
345
|
-
|
|
346
|
-
try {
|
|
347
|
-
for (const record of batch) {
|
|
348
|
-
// Build update query based on action config
|
|
349
|
-
const updateFields = action.actionConfig.updateFields || {};
|
|
350
|
-
const updateValues = Object.keys(updateFields).map((key) => {
|
|
351
|
-
return `${key} = ?`;
|
|
352
|
-
});
|
|
353
|
-
const values = Object.values(updateFields);
|
|
354
|
-
|
|
355
|
-
if (updateValues.length > 0) {
|
|
356
|
-
const tableName = this.getTableNameForEntityType(
|
|
357
|
-
action.targetEntityType,
|
|
358
|
-
);
|
|
359
|
-
await queryRunner.query(
|
|
360
|
-
`UPDATE ${tableName} SET ${updateValues.join(', ')} WHERE id = ?`,
|
|
361
|
-
[...values, record.id],
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
result.processedRecords += 1;
|
|
366
|
-
result.successfulRecords += 1;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
await queryRunner.commitTransaction();
|
|
370
|
-
} catch (error) {
|
|
371
|
-
await queryRunner.rollbackTransaction();
|
|
372
|
-
result.failedRecords += batch.length;
|
|
373
|
-
result.errors.push({
|
|
374
|
-
error: `Batch update failed: ${error.message}`,
|
|
375
|
-
});
|
|
376
|
-
} finally {
|
|
377
|
-
await queryRunner.release();
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
} catch (error) {
|
|
381
|
-
throw new Error(`Update records action failed: ${error.message}`);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
return result;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Execute create task action
|
|
389
|
-
*/
|
|
390
|
-
private async executeCreateTaskAction(
|
|
391
|
-
action: any,
|
|
392
|
-
jobData: ScheduleJobData,
|
|
393
|
-
): Promise<BatchProcessingResult> {
|
|
394
|
-
const result: BatchProcessingResult = {
|
|
395
|
-
totalRecords: 0,
|
|
396
|
-
processedRecords: 0,
|
|
397
|
-
successfulRecords: 0,
|
|
398
|
-
failedRecords: 0,
|
|
399
|
-
errors: [],
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
try {
|
|
403
|
-
// Get target records
|
|
404
|
-
const records = await this.getTargetRecords(
|
|
405
|
-
action.targetEntityType,
|
|
406
|
-
action.filterCriteria,
|
|
407
|
-
jobData,
|
|
408
|
-
);
|
|
409
|
-
|
|
410
|
-
result.totalRecords = records.length;
|
|
411
|
-
|
|
412
|
-
// Task repo (cr_wf_task)
|
|
413
|
-
const taskRepo = this.reflectionHelper.getRepoService('TaskDataEntity');
|
|
414
|
-
|
|
415
|
-
// Process in batches
|
|
416
|
-
const batches = this.chunkArray(records, DEFAULT_BATCH_SIZE);
|
|
417
|
-
|
|
418
|
-
for (const batch of batches) {
|
|
419
|
-
for (const record of batch) {
|
|
420
|
-
try {
|
|
421
|
-
// Build task object
|
|
422
|
-
const task = {
|
|
423
|
-
name: action.actionConfig.taskName || 'Scheduled Task',
|
|
424
|
-
description: action.actionConfig.taskDescription || '',
|
|
425
|
-
status: 'PENDING',
|
|
426
|
-
mapped_entity_id: record.id,
|
|
427
|
-
mapped_entity_type: action.targetEntityType,
|
|
428
|
-
organization_id: jobData.organizationId,
|
|
429
|
-
enterprise_id: jobData.enterpriseId,
|
|
430
|
-
created_by: jobData.createdBy,
|
|
431
|
-
created_date: new Date(), // NOW()
|
|
432
|
-
entity_type: 'WFTK',
|
|
433
|
-
};
|
|
434
|
-
|
|
435
|
-
// Insert using TypeORM repository
|
|
436
|
-
await taskRepo.insert(task);
|
|
437
|
-
|
|
438
|
-
result.processedRecords += 1;
|
|
439
|
-
result.successfulRecords += 1;
|
|
440
|
-
} catch (error) {
|
|
441
|
-
result.processedRecords += 1;
|
|
442
|
-
result.failedRecords += 1;
|
|
443
|
-
|
|
444
|
-
result.errors.push({
|
|
445
|
-
recordId: record.id,
|
|
446
|
-
error: error.message,
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
} catch (error) {
|
|
452
|
-
throw new Error(`Create task action failed: ${error.message}`);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
return result;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Execute send notification action
|
|
460
|
-
*/
|
|
461
|
-
private async executeSendNotificationAction(
|
|
462
|
-
action: any,
|
|
463
|
-
jobData: ScheduleJobData,
|
|
464
|
-
): Promise<BatchProcessingResult> {
|
|
465
|
-
const result: BatchProcessingResult = {
|
|
466
|
-
totalRecords: 0,
|
|
467
|
-
processedRecords: 0,
|
|
468
|
-
successfulRecords: 0,
|
|
469
|
-
failedRecords: 0,
|
|
470
|
-
errors: [],
|
|
471
|
-
};
|
|
472
|
-
|
|
473
|
-
try {
|
|
474
|
-
// Get target records
|
|
475
|
-
const records = await this.getTargetRecords(
|
|
476
|
-
action.targetEntityType,
|
|
477
|
-
action.filterCriteria,
|
|
478
|
-
jobData,
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
result.totalRecords = records.length;
|
|
482
|
-
|
|
483
|
-
// Prepare repo
|
|
484
|
-
const notificationRepo = this.reflectionHelper.getRepoService(
|
|
485
|
-
'NotificationData', // cr_notification repo
|
|
486
|
-
);
|
|
487
|
-
|
|
488
|
-
// Process in batches
|
|
489
|
-
const batches = this.chunkArray(records, DEFAULT_BATCH_SIZE);
|
|
490
|
-
|
|
491
|
-
for (const batch of batches) {
|
|
492
|
-
for (const record of batch) {
|
|
493
|
-
try {
|
|
494
|
-
// Build notification object
|
|
495
|
-
const notification = {
|
|
496
|
-
user_id: record.user_id || jobData.createdBy,
|
|
497
|
-
event_type: action.actionConfig.eventType || 'WORKFLOW_SCHEDULED',
|
|
498
|
-
message:
|
|
499
|
-
action.actionConfig.message || 'Scheduled workflow executed',
|
|
500
|
-
mapped_entity_id: record.id,
|
|
501
|
-
mapped_entity_type: action.targetEntityType,
|
|
502
|
-
is_read: 0,
|
|
503
|
-
organization_id: jobData.organizationId,
|
|
504
|
-
created_date: new Date(), // NOW()
|
|
505
|
-
entity_type: 'NOTF',
|
|
506
|
-
status: 'ACTIVE',
|
|
507
|
-
};
|
|
508
|
-
|
|
509
|
-
// Insert using TypeORM (replaces raw SQL)
|
|
510
|
-
await notificationRepo.insert(notification);
|
|
511
|
-
|
|
512
|
-
result.processedRecords += 1;
|
|
513
|
-
result.successfulRecords += 1;
|
|
514
|
-
} catch (error) {
|
|
515
|
-
result.processedRecords += 1;
|
|
516
|
-
result.failedRecords += 1;
|
|
517
|
-
|
|
518
|
-
result.errors.push({
|
|
519
|
-
recordId: record.id,
|
|
520
|
-
error: error.message,
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
} catch (error) {
|
|
526
|
-
throw new Error(`Send notification action failed: ${error.message}`);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
return result;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
/**
|
|
533
|
-
* Get target records based on entity type and filter criteria
|
|
534
|
-
*/
|
|
535
|
-
private async getTargetRecords(
|
|
536
|
-
entityType: string,
|
|
537
|
-
filterCriteria: any,
|
|
538
|
-
jobData: ScheduleJobData,
|
|
539
|
-
): Promise<any[]> {
|
|
540
|
-
// Get repository dynamically based on entityType
|
|
541
|
-
const repo = this.reflectionHelper.getRepoService(entityType);
|
|
542
|
-
|
|
543
|
-
// Start QueryBuilder
|
|
544
|
-
const qb = repo.createQueryBuilder('e');
|
|
545
|
-
|
|
546
|
-
// Mandatory organization filter
|
|
547
|
-
qb.where('e.organization_id = :orgId', {
|
|
548
|
-
orgId: jobData.organizationId,
|
|
549
|
-
});
|
|
550
|
-
|
|
551
|
-
// Apply additional filters
|
|
552
|
-
if (filterCriteria && Object.keys(filterCriteria).length > 0) {
|
|
553
|
-
for (const key of Object.keys(filterCriteria)) {
|
|
554
|
-
qb.andWhere(`e.${key} = :${key}`, {
|
|
555
|
-
[key]: filterCriteria[key],
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
const records = await qb.getMany();
|
|
561
|
-
return records;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* Get table name for entity type
|
|
566
|
-
*/
|
|
567
|
-
private getTableNameForEntityType(entityType: string): string {
|
|
568
|
-
// Map entity types to table names
|
|
569
|
-
const entityTypeMap: Record<string, string> = {
|
|
570
|
-
USR: 'sso_user',
|
|
571
|
-
LEAD: 'cr_lead',
|
|
572
|
-
TASK: 'cr_wf_task',
|
|
573
|
-
// Add more mappings as needed
|
|
574
|
-
};
|
|
575
|
-
|
|
576
|
-
return entityTypeMap[entityType] || 'unknown_table';
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* Split array into chunks
|
|
581
|
-
*/
|
|
582
|
-
private chunkArray<T>(array: T[], chunkSize: number): T[][] {
|
|
583
|
-
const chunks: T[][] = [];
|
|
584
|
-
for (let i = 0; i < array.length; i += chunkSize) {
|
|
585
|
-
chunks.push(array.slice(i, i + chunkSize));
|
|
586
|
-
}
|
|
587
|
-
return chunks;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
/**
|
|
591
|
-
* Event handler for when job becomes active
|
|
592
|
-
*/
|
|
593
|
-
@OnQueueActive()
|
|
594
|
-
onActive(job: Job<ScheduleJobData>) {
|
|
595
|
-
this.logger.log(
|
|
596
|
-
`Processing job ${job.id} of type ${job.name} for schedule ${job.data.scheduleId}`,
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Event handler for when job completes
|
|
602
|
-
*/
|
|
603
|
-
@OnQueueCompleted()
|
|
604
|
-
onCompleted(job: Job<ScheduleJobData>, result: any) {
|
|
605
|
-
this.logger.log(
|
|
606
|
-
`Job ${job.id} completed for schedule ${job.data.scheduleId} with result: ${JSON.stringify(result)}`,
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
/**
|
|
611
|
-
* Event handler for when job fails
|
|
612
|
-
*/
|
|
613
|
-
@OnQueueFailed()
|
|
614
|
-
onFailed(job: Job<ScheduleJobData>, error: Error) {
|
|
615
|
-
this.logger.error(
|
|
616
|
-
`Job ${job.id} failed for schedule ${job.data.scheduleId} with error: ${error.message}`,
|
|
617
|
-
error.stack,
|
|
618
|
-
);
|
|
619
|
-
}
|
|
620
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
Process,
|
|
3
|
+
Processor,
|
|
4
|
+
OnQueueActive,
|
|
5
|
+
OnQueueCompleted,
|
|
6
|
+
OnQueueFailed,
|
|
7
|
+
} from '@nestjs/bull';
|
|
8
|
+
import { Logger, Inject } from '@nestjs/common';
|
|
9
|
+
import { Job } from 'bull';
|
|
10
|
+
import { InjectRepository } from '@nestjs/typeorm';
|
|
11
|
+
import { Repository, DataSource } from 'typeorm';
|
|
12
|
+
import { ScheduledWorkflow } from '../entities/scheduled-workflow.entity';
|
|
13
|
+
import { WorkflowExecutionLog } from '../entities/workflow-execution-log.entity';
|
|
14
|
+
import {
|
|
15
|
+
WORKFLOW_SCHEDULE_QUEUE,
|
|
16
|
+
EXECUTE_SCHEDULED_WORKFLOW_JOB,
|
|
17
|
+
EXECUTION_STATUS_PENDING,
|
|
18
|
+
EXECUTION_STATUS_RUNNING,
|
|
19
|
+
EXECUTION_STATUS_COMPLETED,
|
|
20
|
+
EXECUTION_STATUS_FAILED,
|
|
21
|
+
EXECUTION_STATUS_PARTIAL,
|
|
22
|
+
DEFAULT_BATCH_SIZE,
|
|
23
|
+
} from '../constants/schedule.constants';
|
|
24
|
+
import {
|
|
25
|
+
ScheduleJobData,
|
|
26
|
+
BatchProcessingResult,
|
|
27
|
+
} from '../interfaces/schedule-job-data.interface';
|
|
28
|
+
import { ScheduleHandlerService } from 'src/module/workflow-automation/service/schedule-handler.service';
|
|
29
|
+
import { ReflectionHelper } from 'src/utils/service/reflection-helper.service';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Schedule Processor
|
|
33
|
+
* Processes scheduled workflow execution jobs from Bull queue
|
|
34
|
+
*/
|
|
35
|
+
@Processor(WORKFLOW_SCHEDULE_QUEUE)
|
|
36
|
+
export class ScheduleProcessor {
|
|
37
|
+
private readonly logger = new Logger(ScheduleProcessor.name);
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
@InjectRepository(ScheduledWorkflow)
|
|
41
|
+
private readonly scheduledWorkflowRepository: Repository<ScheduledWorkflow>,
|
|
42
|
+
@InjectRepository(WorkflowExecutionLog)
|
|
43
|
+
private readonly executionLogRepository: Repository<WorkflowExecutionLog>,
|
|
44
|
+
@Inject('ScheduleHandlerService')
|
|
45
|
+
private readonly scheduleHandlerService: ScheduleHandlerService,
|
|
46
|
+
private readonly reflectionHelper: ReflectionHelper,
|
|
47
|
+
private readonly dataSource: DataSource
|
|
48
|
+
) {}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Main job processor for scheduled workflow execution
|
|
52
|
+
*/
|
|
53
|
+
@Process(EXECUTE_SCHEDULED_WORKFLOW_JOB)
|
|
54
|
+
async handleScheduledWorkflowExecution(job: Job<ScheduleJobData>) {
|
|
55
|
+
const { scheduleId, workflowId, organizationId, triggeredBy, createdBy } =
|
|
56
|
+
job.data;
|
|
57
|
+
|
|
58
|
+
this.logger.log(
|
|
59
|
+
`🚀 [handleScheduledWorkflowExecution] Invoked for scheduleId=${scheduleId}, workflowId=${workflowId}`,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Create execution log entry
|
|
63
|
+
const executionLog = this.executionLogRepository.create({
|
|
64
|
+
schedule_id: scheduleId,
|
|
65
|
+
workflow_id: workflowId,
|
|
66
|
+
job_id: job.id.toString(),
|
|
67
|
+
execution_status: EXECUTION_STATUS_PENDING,
|
|
68
|
+
triggered_by: triggeredBy,
|
|
69
|
+
triggered_by_user_id: triggeredBy === 'MANUAL' ? createdBy : null,
|
|
70
|
+
organization_id: organizationId,
|
|
71
|
+
enterprise_id: job.data.enterpriseId,
|
|
72
|
+
created_by: createdBy,
|
|
73
|
+
entity_type: 'WFEL',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.logger.debug(`🧾 Creating execution log for jobId=${job.id}`);
|
|
77
|
+
await this.executionLogRepository.save(executionLog);
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
// Update status to running
|
|
81
|
+
executionLog.execution_status = EXECUTION_STATUS_RUNNING;
|
|
82
|
+
executionLog.started_at = new Date();
|
|
83
|
+
await this.executionLogRepository.save(executionLog);
|
|
84
|
+
|
|
85
|
+
this.logger.log(
|
|
86
|
+
`🏃 Workflow execution started for scheduleId=${scheduleId}`,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Get scheduled workflow details
|
|
90
|
+
const schedule = await this.scheduledWorkflowRepository.findOne({
|
|
91
|
+
where: { id: scheduleId },
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!schedule) {
|
|
95
|
+
throw new Error(`Scheduled workflow not found: ${scheduleId}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.logger.debug(
|
|
99
|
+
`📋 Loaded schedule from DB: ${JSON.stringify(schedule)}`,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Execute workflow actions
|
|
103
|
+
this.logger.log(`⚙️ Executing workflow actions...`);
|
|
104
|
+
const result = await this.executeWorkflowActions(schedule, job.data);
|
|
105
|
+
this.logger.debug(`🧮 Execution result: ${JSON.stringify(result)}`);
|
|
106
|
+
|
|
107
|
+
// Update execution log with results
|
|
108
|
+
const completedAt = new Date();
|
|
109
|
+
executionLog.execution_status =
|
|
110
|
+
result.failedRecords > 0 && result.successfulRecords > 0
|
|
111
|
+
? EXECUTION_STATUS_PARTIAL
|
|
112
|
+
: result.failedRecords > 0
|
|
113
|
+
? EXECUTION_STATUS_FAILED
|
|
114
|
+
: EXECUTION_STATUS_COMPLETED;
|
|
115
|
+
executionLog.completed_at = completedAt;
|
|
116
|
+
executionLog.duration_ms =
|
|
117
|
+
completedAt.getTime() - executionLog.started_at.getTime();
|
|
118
|
+
executionLog.total_records = result.totalRecords;
|
|
119
|
+
executionLog.successful_records = result.successfulRecords;
|
|
120
|
+
executionLog.failed_records = result.failedRecords;
|
|
121
|
+
executionLog.execution_details = {
|
|
122
|
+
batchesProcessed: Math.ceil(result.totalRecords / DEFAULT_BATCH_SIZE),
|
|
123
|
+
errors: result.errors,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
await this.executionLogRepository.save(executionLog);
|
|
127
|
+
|
|
128
|
+
// Update schedule execution count and last execution time
|
|
129
|
+
schedule.execution_count += 1;
|
|
130
|
+
schedule.last_execution_at = completedAt;
|
|
131
|
+
await this.scheduledWorkflowRepository.save(schedule);
|
|
132
|
+
|
|
133
|
+
this.logger.log(
|
|
134
|
+
`✅ Workflow execution completed: scheduleId=${scheduleId}, status=${executionLog.execution_status}, processed=${result.totalRecords}`,
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
success: true,
|
|
139
|
+
executionLogId: executionLog.id,
|
|
140
|
+
result,
|
|
141
|
+
};
|
|
142
|
+
} catch (error) {
|
|
143
|
+
this.logger.error(
|
|
144
|
+
`🔥 Workflow execution failed: scheduleId=${scheduleId}, error=${error.message}`,
|
|
145
|
+
error.stack,
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
// Update execution log with error
|
|
149
|
+
executionLog.execution_status = EXECUTION_STATUS_FAILED;
|
|
150
|
+
executionLog.completed_at = new Date();
|
|
151
|
+
executionLog.duration_ms = executionLog.started_at
|
|
152
|
+
? executionLog.completed_at.getTime() -
|
|
153
|
+
executionLog.started_at.getTime()
|
|
154
|
+
: 0;
|
|
155
|
+
executionLog.error_message = error.message;
|
|
156
|
+
executionLog.error_stack = error.stack;
|
|
157
|
+
|
|
158
|
+
await this.executionLogRepository.save(executionLog);
|
|
159
|
+
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Execute all actions defined in the workflow
|
|
166
|
+
*/
|
|
167
|
+
private async executeWorkflowActions(
|
|
168
|
+
schedule: ScheduledWorkflow,
|
|
169
|
+
jobData: ScheduleJobData,
|
|
170
|
+
): Promise<BatchProcessingResult> {
|
|
171
|
+
const result: BatchProcessingResult = {
|
|
172
|
+
totalRecords: 0,
|
|
173
|
+
processedRecords: 0,
|
|
174
|
+
successfulRecords: 0,
|
|
175
|
+
failedRecords: 0,
|
|
176
|
+
errors: [],
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const resultData: any =
|
|
180
|
+
await this.scheduleHandlerService.handleScheduledWorkflow(
|
|
181
|
+
jobData.workflowId,
|
|
182
|
+
jobData,
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
if (!schedule.actions || schedule.actions.length === 0) {
|
|
186
|
+
this.logger.warn(`No actions defined for schedule: ${schedule.id}`);
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Execute each action sequentially
|
|
191
|
+
for (const action of schedule.actions) {
|
|
192
|
+
try {
|
|
193
|
+
const actionResult = await this.executeAction(action, jobData);
|
|
194
|
+
result.totalRecords += actionResult.totalRecords;
|
|
195
|
+
result.processedRecords += actionResult.processedRecords;
|
|
196
|
+
result.successfulRecords += actionResult.successfulRecords;
|
|
197
|
+
result.failedRecords += actionResult.failedRecords;
|
|
198
|
+
result.errors.push(...actionResult.errors);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
this.logger.error(
|
|
201
|
+
`Action execution failed: actionType=${action.actionType}, error=${error.message}`,
|
|
202
|
+
);
|
|
203
|
+
result.failedRecords += 1;
|
|
204
|
+
result.errors.push({
|
|
205
|
+
error: `Action ${action.actionType} failed: ${error.message}`,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return resultData;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Execute a single workflow action
|
|
215
|
+
*/
|
|
216
|
+
private async executeAction(action: any, jobData: ScheduleJobData) {
|
|
217
|
+
this.logger.log(`🚀 Executing scheduled action: ${action.actionType}`);
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
// We’ll assume jobData contains workflowId and user info
|
|
221
|
+
const { workflowId, loggedInUser } = jobData;
|
|
222
|
+
|
|
223
|
+
// 🧠 Call your handler that performs filtering and workflow execution
|
|
224
|
+
const result: any =
|
|
225
|
+
await this.scheduleHandlerService.handleScheduledWorkflow(
|
|
226
|
+
workflowId,
|
|
227
|
+
loggedInUser,
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
this.logger.log(
|
|
231
|
+
`✅ Scheduled workflow ${workflowId} executed successfully`,
|
|
232
|
+
);
|
|
233
|
+
return {
|
|
234
|
+
totalRecords: result?.length || 0,
|
|
235
|
+
processedRecords: result?.length || 0,
|
|
236
|
+
successfulRecords: result?.length || 0,
|
|
237
|
+
failedRecords: 0,
|
|
238
|
+
errors: [],
|
|
239
|
+
};
|
|
240
|
+
} catch (error) {
|
|
241
|
+
this.logger.error(
|
|
242
|
+
`🔥 Error executing scheduled workflow action: ${error.message}`,
|
|
243
|
+
error.stack,
|
|
244
|
+
);
|
|
245
|
+
return {
|
|
246
|
+
totalRecords: 0,
|
|
247
|
+
processedRecords: 0,
|
|
248
|
+
successfulRecords: 0,
|
|
249
|
+
failedRecords: 1,
|
|
250
|
+
errors: [{ error: error.message }],
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Execute send email action
|
|
257
|
+
*/
|
|
258
|
+
private async executeSendEmailAction(
|
|
259
|
+
action: any,
|
|
260
|
+
jobData: ScheduleJobData,
|
|
261
|
+
): Promise<BatchProcessingResult> {
|
|
262
|
+
const result: BatchProcessingResult = {
|
|
263
|
+
totalRecords: 0,
|
|
264
|
+
processedRecords: 0,
|
|
265
|
+
successfulRecords: 0,
|
|
266
|
+
failedRecords: 0,
|
|
267
|
+
errors: [],
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
// Get target records based on filter criteria
|
|
272
|
+
const records = await this.getTargetRecords(
|
|
273
|
+
action.targetEntityType,
|
|
274
|
+
action.filterCriteria,
|
|
275
|
+
jobData,
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
result.totalRecords = records.length;
|
|
279
|
+
|
|
280
|
+
// Process in batches
|
|
281
|
+
const batches = this.chunkArray(records, DEFAULT_BATCH_SIZE);
|
|
282
|
+
|
|
283
|
+
for (const batch of batches) {
|
|
284
|
+
for (const record of batch) {
|
|
285
|
+
try {
|
|
286
|
+
// TODO: Integrate with email service
|
|
287
|
+
// await this.emailService.sendEmail({
|
|
288
|
+
// to: record.email,
|
|
289
|
+
// subject: action.actionConfig.subject,
|
|
290
|
+
// template: action.actionConfig.template,
|
|
291
|
+
// data: record,
|
|
292
|
+
// });
|
|
293
|
+
|
|
294
|
+
result.processedRecords += 1;
|
|
295
|
+
result.successfulRecords += 1;
|
|
296
|
+
} catch (error) {
|
|
297
|
+
result.processedRecords += 1;
|
|
298
|
+
result.failedRecords += 1;
|
|
299
|
+
result.errors.push({
|
|
300
|
+
recordId: record.id,
|
|
301
|
+
error: error.message,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
} catch (error) {
|
|
307
|
+
throw new Error(`Send email action failed: ${error.message}`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Execute update records action
|
|
315
|
+
*/
|
|
316
|
+
private async executeUpdateRecordsAction(
|
|
317
|
+
action: any,
|
|
318
|
+
jobData: ScheduleJobData,
|
|
319
|
+
): Promise<BatchProcessingResult> {
|
|
320
|
+
const result: BatchProcessingResult = {
|
|
321
|
+
totalRecords: 0,
|
|
322
|
+
processedRecords: 0,
|
|
323
|
+
successfulRecords: 0,
|
|
324
|
+
failedRecords: 0,
|
|
325
|
+
errors: [],
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
// Get target records
|
|
330
|
+
const records = await this.getTargetRecords(
|
|
331
|
+
action.targetEntityType,
|
|
332
|
+
action.filterCriteria,
|
|
333
|
+
jobData,
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
result.totalRecords = records.length;
|
|
337
|
+
|
|
338
|
+
// Process in batches
|
|
339
|
+
const batches = this.chunkArray(records, DEFAULT_BATCH_SIZE);
|
|
340
|
+
|
|
341
|
+
for (const batch of batches) {
|
|
342
|
+
const queryRunner = this.dataSource.createQueryRunner();
|
|
343
|
+
await queryRunner.connect();
|
|
344
|
+
await queryRunner.startTransaction();
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
for (const record of batch) {
|
|
348
|
+
// Build update query based on action config
|
|
349
|
+
const updateFields = action.actionConfig.updateFields || {};
|
|
350
|
+
const updateValues = Object.keys(updateFields).map((key) => {
|
|
351
|
+
return `${key} = ?`;
|
|
352
|
+
});
|
|
353
|
+
const values = Object.values(updateFields);
|
|
354
|
+
|
|
355
|
+
if (updateValues.length > 0) {
|
|
356
|
+
const tableName = this.getTableNameForEntityType(
|
|
357
|
+
action.targetEntityType,
|
|
358
|
+
);
|
|
359
|
+
await queryRunner.query(
|
|
360
|
+
`UPDATE ${tableName} SET ${updateValues.join(', ')} WHERE id = ?`,
|
|
361
|
+
[...values, record.id],
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
result.processedRecords += 1;
|
|
366
|
+
result.successfulRecords += 1;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
await queryRunner.commitTransaction();
|
|
370
|
+
} catch (error) {
|
|
371
|
+
await queryRunner.rollbackTransaction();
|
|
372
|
+
result.failedRecords += batch.length;
|
|
373
|
+
result.errors.push({
|
|
374
|
+
error: `Batch update failed: ${error.message}`,
|
|
375
|
+
});
|
|
376
|
+
} finally {
|
|
377
|
+
await queryRunner.release();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
} catch (error) {
|
|
381
|
+
throw new Error(`Update records action failed: ${error.message}`);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return result;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Execute create task action
|
|
389
|
+
*/
|
|
390
|
+
private async executeCreateTaskAction(
|
|
391
|
+
action: any,
|
|
392
|
+
jobData: ScheduleJobData,
|
|
393
|
+
): Promise<BatchProcessingResult> {
|
|
394
|
+
const result: BatchProcessingResult = {
|
|
395
|
+
totalRecords: 0,
|
|
396
|
+
processedRecords: 0,
|
|
397
|
+
successfulRecords: 0,
|
|
398
|
+
failedRecords: 0,
|
|
399
|
+
errors: [],
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
// Get target records
|
|
404
|
+
const records = await this.getTargetRecords(
|
|
405
|
+
action.targetEntityType,
|
|
406
|
+
action.filterCriteria,
|
|
407
|
+
jobData,
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
result.totalRecords = records.length;
|
|
411
|
+
|
|
412
|
+
// Task repo (cr_wf_task)
|
|
413
|
+
const taskRepo = this.reflectionHelper.getRepoService('TaskDataEntity');
|
|
414
|
+
|
|
415
|
+
// Process in batches
|
|
416
|
+
const batches = this.chunkArray(records, DEFAULT_BATCH_SIZE);
|
|
417
|
+
|
|
418
|
+
for (const batch of batches) {
|
|
419
|
+
for (const record of batch) {
|
|
420
|
+
try {
|
|
421
|
+
// Build task object
|
|
422
|
+
const task = {
|
|
423
|
+
name: action.actionConfig.taskName || 'Scheduled Task',
|
|
424
|
+
description: action.actionConfig.taskDescription || '',
|
|
425
|
+
status: 'PENDING',
|
|
426
|
+
mapped_entity_id: record.id,
|
|
427
|
+
mapped_entity_type: action.targetEntityType,
|
|
428
|
+
organization_id: jobData.organizationId,
|
|
429
|
+
enterprise_id: jobData.enterpriseId,
|
|
430
|
+
created_by: jobData.createdBy,
|
|
431
|
+
created_date: new Date(), // NOW()
|
|
432
|
+
entity_type: 'WFTK',
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// Insert using TypeORM repository
|
|
436
|
+
await taskRepo.insert(task);
|
|
437
|
+
|
|
438
|
+
result.processedRecords += 1;
|
|
439
|
+
result.successfulRecords += 1;
|
|
440
|
+
} catch (error) {
|
|
441
|
+
result.processedRecords += 1;
|
|
442
|
+
result.failedRecords += 1;
|
|
443
|
+
|
|
444
|
+
result.errors.push({
|
|
445
|
+
recordId: record.id,
|
|
446
|
+
error: error.message,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
} catch (error) {
|
|
452
|
+
throw new Error(`Create task action failed: ${error.message}`);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Execute send notification action
|
|
460
|
+
*/
|
|
461
|
+
private async executeSendNotificationAction(
|
|
462
|
+
action: any,
|
|
463
|
+
jobData: ScheduleJobData,
|
|
464
|
+
): Promise<BatchProcessingResult> {
|
|
465
|
+
const result: BatchProcessingResult = {
|
|
466
|
+
totalRecords: 0,
|
|
467
|
+
processedRecords: 0,
|
|
468
|
+
successfulRecords: 0,
|
|
469
|
+
failedRecords: 0,
|
|
470
|
+
errors: [],
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
try {
|
|
474
|
+
// Get target records
|
|
475
|
+
const records = await this.getTargetRecords(
|
|
476
|
+
action.targetEntityType,
|
|
477
|
+
action.filterCriteria,
|
|
478
|
+
jobData,
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
result.totalRecords = records.length;
|
|
482
|
+
|
|
483
|
+
// Prepare repo
|
|
484
|
+
const notificationRepo = this.reflectionHelper.getRepoService(
|
|
485
|
+
'NotificationData', // cr_notification repo
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
// Process in batches
|
|
489
|
+
const batches = this.chunkArray(records, DEFAULT_BATCH_SIZE);
|
|
490
|
+
|
|
491
|
+
for (const batch of batches) {
|
|
492
|
+
for (const record of batch) {
|
|
493
|
+
try {
|
|
494
|
+
// Build notification object
|
|
495
|
+
const notification = {
|
|
496
|
+
user_id: record.user_id || jobData.createdBy,
|
|
497
|
+
event_type: action.actionConfig.eventType || 'WORKFLOW_SCHEDULED',
|
|
498
|
+
message:
|
|
499
|
+
action.actionConfig.message || 'Scheduled workflow executed',
|
|
500
|
+
mapped_entity_id: record.id,
|
|
501
|
+
mapped_entity_type: action.targetEntityType,
|
|
502
|
+
is_read: 0,
|
|
503
|
+
organization_id: jobData.organizationId,
|
|
504
|
+
created_date: new Date(), // NOW()
|
|
505
|
+
entity_type: 'NOTF',
|
|
506
|
+
status: 'ACTIVE',
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
// Insert using TypeORM (replaces raw SQL)
|
|
510
|
+
await notificationRepo.insert(notification);
|
|
511
|
+
|
|
512
|
+
result.processedRecords += 1;
|
|
513
|
+
result.successfulRecords += 1;
|
|
514
|
+
} catch (error) {
|
|
515
|
+
result.processedRecords += 1;
|
|
516
|
+
result.failedRecords += 1;
|
|
517
|
+
|
|
518
|
+
result.errors.push({
|
|
519
|
+
recordId: record.id,
|
|
520
|
+
error: error.message,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
} catch (error) {
|
|
526
|
+
throw new Error(`Send notification action failed: ${error.message}`);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return result;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Get target records based on entity type and filter criteria
|
|
534
|
+
*/
|
|
535
|
+
private async getTargetRecords(
|
|
536
|
+
entityType: string,
|
|
537
|
+
filterCriteria: any,
|
|
538
|
+
jobData: ScheduleJobData,
|
|
539
|
+
): Promise<any[]> {
|
|
540
|
+
// Get repository dynamically based on entityType
|
|
541
|
+
const repo = this.reflectionHelper.getRepoService(entityType);
|
|
542
|
+
|
|
543
|
+
// Start QueryBuilder
|
|
544
|
+
const qb = repo.createQueryBuilder('e');
|
|
545
|
+
|
|
546
|
+
// Mandatory organization filter
|
|
547
|
+
qb.where('e.organization_id = :orgId', {
|
|
548
|
+
orgId: jobData.organizationId,
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// Apply additional filters
|
|
552
|
+
if (filterCriteria && Object.keys(filterCriteria).length > 0) {
|
|
553
|
+
for (const key of Object.keys(filterCriteria)) {
|
|
554
|
+
qb.andWhere(`e.${key} = :${key}`, {
|
|
555
|
+
[key]: filterCriteria[key],
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const records = await qb.getMany();
|
|
561
|
+
return records;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Get table name for entity type
|
|
566
|
+
*/
|
|
567
|
+
private getTableNameForEntityType(entityType: string): string {
|
|
568
|
+
// Map entity types to table names
|
|
569
|
+
const entityTypeMap: Record<string, string> = {
|
|
570
|
+
USR: 'sso_user',
|
|
571
|
+
LEAD: 'cr_lead',
|
|
572
|
+
TASK: 'cr_wf_task',
|
|
573
|
+
// Add more mappings as needed
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
return entityTypeMap[entityType] || 'unknown_table';
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Split array into chunks
|
|
581
|
+
*/
|
|
582
|
+
private chunkArray<T>(array: T[], chunkSize: number): T[][] {
|
|
583
|
+
const chunks: T[][] = [];
|
|
584
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
585
|
+
chunks.push(array.slice(i, i + chunkSize));
|
|
586
|
+
}
|
|
587
|
+
return chunks;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Event handler for when job becomes active
|
|
592
|
+
*/
|
|
593
|
+
@OnQueueActive()
|
|
594
|
+
onActive(job: Job<ScheduleJobData>) {
|
|
595
|
+
this.logger.log(
|
|
596
|
+
`Processing job ${job.id} of type ${job.name} for schedule ${job.data.scheduleId}`,
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Event handler for when job completes
|
|
602
|
+
*/
|
|
603
|
+
@OnQueueCompleted()
|
|
604
|
+
onCompleted(job: Job<ScheduleJobData>, result: any) {
|
|
605
|
+
this.logger.log(
|
|
606
|
+
`Job ${job.id} completed for schedule ${job.data.scheduleId} with result: ${JSON.stringify(result)}`,
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Event handler for when job fails
|
|
612
|
+
*/
|
|
613
|
+
@OnQueueFailed()
|
|
614
|
+
onFailed(job: Job<ScheduleJobData>, error: Error) {
|
|
615
|
+
this.logger.error(
|
|
616
|
+
`Job ${job.id} failed for schedule ${job.data.scheduleId} with error: ${error.message}`,
|
|
617
|
+
error.stack,
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
}
|