rez_core 5.0.42 → 5.0.44

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.
Files changed (425) hide show
  1. package/.idea/250218_nodejs_core.iml +11 -8
  2. package/.idea/codeStyles/Project.xml +58 -58
  3. package/.idea/codeStyles/codeStyleConfig.xml +4 -4
  4. package/.idea/inspectionProfiles/Project_Default.xml +1 -1
  5. package/.idea/modules.xml +7 -7
  6. package/.idea/prettier.xml +5 -5
  7. package/.idea/vcs.xml +5 -5
  8. package/.prettierrc +3 -3
  9. package/README.md +99 -99
  10. package/dist/module/auth/guards/role.guard.js +3 -3
  11. package/dist/module/auth/services/auth.service.js +2 -2
  12. package/dist/module/filter/repository/saved-filter.repository.js +4 -4
  13. package/dist/module/filter/service/filter-evaluator.service.js +2 -2
  14. package/dist/module/filter/service/filter.service.js +118 -69
  15. package/dist/module/filter/service/filter.service.js.map +1 -1
  16. package/dist/module/integration/examples/usage.example.js +9 -9
  17. package/dist/module/integration/service/integration.service.js +1 -1
  18. package/dist/module/integration/service/wrapper.service.js +26 -26
  19. package/dist/module/listmaster/service/list-master-item.service.js +2 -2
  20. package/dist/module/mapper/service/field-mapper.service.js +4 -4
  21. package/dist/module/meta/repository/entity-attribute-update.repository.js +3 -3
  22. package/dist/module/meta/repository/entity-master.repository.js +6 -6
  23. package/dist/module/meta/service/entity-dynamic.service.js +44 -44
  24. package/dist/module/meta/service/entity-list.service.js +3 -3
  25. package/dist/module/meta/service/entity-relation.service.js +9 -9
  26. package/dist/module/meta/service/entity-service-impl.service.js +3 -3
  27. package/dist/module/meta/service/populate-meta.service.js +3 -0
  28. package/dist/module/meta/service/populate-meta.service.js.map +1 -1
  29. package/dist/module/meta/service/resolver.service.js +3 -3
  30. package/dist/module/module/repository/menu.repository.js +17 -17
  31. package/dist/module/notification/service/notification.service.js +10 -10
  32. package/dist/module/user/controller/login.controller.js +18 -18
  33. package/dist/module/user/service/role.service.js +4 -4
  34. package/dist/module/user/service/user-session.service.js +2 -2
  35. package/dist/module/workflow/repository/action.repository.js +20 -20
  36. package/dist/module/workflow/repository/comm-template.repository.js +6 -6
  37. package/dist/module/workflow/repository/form-master.repository.js +2 -2
  38. package/dist/module/workflow/repository/stage-group.repository.js +20 -20
  39. package/dist/module/workflow/repository/stage-movement.repository.js +17 -17
  40. package/dist/module/workflow/repository/stage.repository.js +8 -8
  41. package/dist/module/workflow/service/action-template-mapping.service.js +13 -13
  42. package/dist/module/workflow/service/action.service.js +7 -7
  43. package/dist/module/workflow/service/entity-modification.service.js +2 -2
  44. package/dist/module/workflow/service/stage-group.service.js +2 -2
  45. package/dist/module/workflow/service/stage.service.js +2 -2
  46. package/dist/module/workflow/service/task.service.js +35 -35
  47. package/dist/module/workflow/service/workflow-list-master.service.js +15 -15
  48. package/dist/module/workflow/service/workflow-meta.service.js +26 -26
  49. package/dist/module/workflow/service/workflow.service.js +2 -2
  50. package/dist/module/workflow-automation/service/schedule-handler.service.js +9 -9
  51. package/dist/module/workflow-schedule/processors/schedule.processor.js +4 -4
  52. package/dist/module/workflow-schedule/service/workflow-schedule.service.js +9 -9
  53. package/dist/tsconfig.build.tsbuildinfo +1 -1
  54. package/dist/utils/service/reflection-helper.service.js +2 -2
  55. package/docs/modules/event-driven-integration-design.md +91 -91
  56. package/docs/modules/integration.md +250 -250
  57. package/eslint.config.mjs +34 -34
  58. package/nest-cli.json +14 -14
  59. package/package.json +124 -124
  60. package/src/app.controller.ts +12 -12
  61. package/src/app.module.ts +66 -66
  62. package/src/app.service.ts +8 -8
  63. package/src/config/bull.config.ts +69 -69
  64. package/src/config/config.module.ts +17 -17
  65. package/src/config/database.config.ts +48 -48
  66. package/src/constant/global.constant.ts +67 -67
  67. package/src/core.module.ts +91 -91
  68. package/src/decorators/roles.decorator.ts +7 -7
  69. package/src/dtos/response.dto.ts +6 -6
  70. package/src/dtos/response.ts +5 -5
  71. package/src/index.ts +1 -1
  72. package/src/module/auth/auth.module.ts +49 -49
  73. package/src/module/auth/controller/auth.controller.ts +28 -28
  74. package/src/module/auth/guards/google-auth.guard.ts +9 -9
  75. package/src/module/auth/guards/jwt.guard.ts +22 -22
  76. package/src/module/auth/guards/role.guard.ts +68 -68
  77. package/src/module/auth/services/auth.service.ts +50 -50
  78. package/src/module/auth/services/jwt.service.ts +11 -11
  79. package/src/module/auth/strategies/google.strategy.ts +54 -54
  80. package/src/module/auth/strategies/jwt.strategy.ts +58 -58
  81. package/src/module/auth/strategies/local.strategy.ts +13 -13
  82. package/src/module/dashboard/controller/dashboard.controller.ts +36 -36
  83. package/src/module/dashboard/dashboard.module.ts +21 -21
  84. package/src/module/dashboard/entity/dashboard_page_data.entity.ts +27 -27
  85. package/src/module/dashboard/entity/widget_master.entity.ts +18 -18
  86. package/src/module/dashboard/repository/dashboard.repository.ts +42 -42
  87. package/src/module/dashboard/service/dashboard.service.ts +73 -73
  88. package/src/module/dev/dev.module.ts +12 -12
  89. package/src/module/dev/service/dev.service.ts +7 -7
  90. package/src/module/enterprise/controller/organization.controller.ts +36 -36
  91. package/src/module/enterprise/enterprise.module.ts +30 -30
  92. package/src/module/enterprise/entity/enterprise.entity.ts +37 -37
  93. package/src/module/enterprise/entity/organization-app-mapping.entity.ts +13 -13
  94. package/src/module/enterprise/entity/organization.entity.ts +92 -92
  95. package/src/module/enterprise/repository/enterprise.repository.ts +31 -31
  96. package/src/module/enterprise/repository/organization.repository.ts +26 -26
  97. package/src/module/enterprise/repository/school.repository.ts +278 -278
  98. package/src/module/enterprise/service/brand.service.ts +5 -5
  99. package/src/module/enterprise/service/enterprise.service.ts +16 -16
  100. package/src/module/enterprise/service/organization-app-mapping.service.ts +4 -4
  101. package/src/module/enterprise/service/organization.service.ts +145 -145
  102. package/src/module/entity_json/controller/entity_json.controller.ts +47 -47
  103. package/src/module/entity_json/entity/entityJson.entity.ts +39 -39
  104. package/src/module/entity_json/entity_json.module.ts +18 -18
  105. package/src/module/entity_json/service/entityJson.repository.ts +37 -37
  106. package/src/module/entity_json/service/entity_json.service.ts +234 -234
  107. package/src/module/filter/controller/filter.controller.ts +84 -84
  108. package/src/module/filter/dto/filter-request.dto.ts +38 -38
  109. package/src/module/filter/entity/saved-filter-detail.entity.ts +41 -41
  110. package/src/module/filter/entity/saved-filter-master.entity.ts +23 -23
  111. package/src/module/filter/filter.module.ts +31 -31
  112. package/src/module/filter/repository/saved-filter.repository.ts +168 -168
  113. package/src/module/filter/service/filter-evaluator.service.ts +86 -86
  114. package/src/module/filter/service/filter.service.ts +1235 -1144
  115. package/src/module/filter/service/saved-filter.service.ts +170 -170
  116. package/src/module/ics/controller/ics.controller.ts +21 -21
  117. package/src/module/ics/dto/ics.dto.ts +55 -55
  118. package/src/module/ics/ics.module.ts +13 -13
  119. package/src/module/ics/service/ics.service.ts +57 -57
  120. package/src/module/integration/controller/calender-event.controller.ts +31 -31
  121. package/src/module/integration/controller/integration.controller.ts +662 -662
  122. package/src/module/integration/controller/wrapper.controller.ts +37 -37
  123. package/src/module/integration/dto/create-config.dto.ts +526 -526
  124. package/src/module/integration/entity/integration-config.entity.ts +112 -112
  125. package/src/module/integration/entity/integration-entity-mapper.entity.ts +14 -14
  126. package/src/module/integration/entity/integration-source.entity.ts +17 -17
  127. package/src/module/integration/entity/user-integration.entity.ts +71 -71
  128. package/src/module/integration/examples/usage.example.ts +338 -338
  129. package/src/module/integration/factories/base.factory.ts +7 -7
  130. package/src/module/integration/factories/email.factory.ts +49 -49
  131. package/src/module/integration/factories/integration.factory.ts +121 -121
  132. package/src/module/integration/factories/sms.factory.ts +51 -51
  133. package/src/module/integration/factories/telephone.factory.ts +41 -41
  134. package/src/module/integration/factories/whatsapp.factory.ts +56 -56
  135. package/src/module/integration/integration.module.ts +110 -110
  136. package/src/module/integration/service/calendar-event.service.ts +118 -118
  137. package/src/module/integration/service/integration-entity-mapper.service.ts +17 -17
  138. package/src/module/integration/service/integration-queue.service.ts +229 -229
  139. package/src/module/integration/service/integration.service.ts +2633 -2633
  140. package/src/module/integration/service/oauth.service.ts +224 -224
  141. package/src/module/integration/service/wrapper.service.ts +701 -701
  142. package/src/module/integration/strategies/email/gmail-api.strategy.ts +280 -280
  143. package/src/module/integration/strategies/email/outlook-api.strategy.ts +44 -44
  144. package/src/module/integration/strategies/email/outlook.strategy.ts +64 -64
  145. package/src/module/integration/strategies/email/sendgrid-api.strategy.ts +260 -260
  146. package/src/module/integration/strategies/integration.strategy.ts +97 -97
  147. package/src/module/integration/strategies/sms/gupshup-sms.strategy.ts +146 -146
  148. package/src/module/integration/strategies/sms/msg91-sms.strategy.ts +164 -164
  149. package/src/module/integration/strategies/sms/tubelight-sms.strategy.ts +163 -163
  150. package/src/module/integration/strategies/telephone/ozonetel-voice.strategy.ts +238 -238
  151. package/src/module/integration/strategies/telephone/tubelight-voice.strategy.ts +210 -210
  152. package/src/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.ts +359 -359
  153. package/src/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.ts +372 -372
  154. package/src/module/integration/strategies/whatsapp/whatsapp-cloud.strategy.ts +403 -403
  155. package/src/module/integration/strategies/whatsapp/whatsapp.strategy.ts +57 -57
  156. package/src/module/layout/controller/layout.controller.ts +47 -47
  157. package/src/module/layout/entity/header-items.entity.ts +28 -28
  158. package/src/module/layout/entity/header-section.entity.ts +19 -19
  159. package/src/module/layout/layout.module.ts +21 -21
  160. package/src/module/layout/repository/header-items.repository.ts +18 -18
  161. package/src/module/layout/repository/header-section.repository.ts +22 -22
  162. package/src/module/layout/service/header-section.service.ts +25 -25
  163. package/src/module/layout_preference/controller/layout_preference.controller.ts +73 -73
  164. package/src/module/layout_preference/entity/layout_preference.entity.ts +28 -28
  165. package/src/module/layout_preference/layout_preference.module.ts +22 -22
  166. package/src/module/layout_preference/repository/layout_preference.repository.ts +65 -65
  167. package/src/module/layout_preference/service/layout_preference.service.ts +191 -191
  168. package/src/module/lead/controller/lead.controller.ts +30 -30
  169. package/src/module/lead/lead.module.ts +14 -14
  170. package/src/module/lead/repository/lead.repository.ts +41 -41
  171. package/src/module/lead/service/lead.service.ts +54 -54
  172. package/src/module/linked_attributes/controller/linked_attributes.controller.ts +37 -37
  173. package/src/module/linked_attributes/entity/linked_attribute.entity.ts +51 -51
  174. package/src/module/linked_attributes/linked_attributes.module.ts +16 -16
  175. package/src/module/linked_attributes/repository/linked_attribute.repository.ts +12 -12
  176. package/src/module/linked_attributes/service/linked_attributes.service.ts +75 -75
  177. package/src/module/listmaster/controller/list-master.controller.ts +230 -230
  178. package/src/module/listmaster/entity/list-master-items.entity.ts +43 -43
  179. package/src/module/listmaster/entity/list-master.entity.ts +33 -33
  180. package/src/module/listmaster/listmaster.module.ts +46 -46
  181. package/src/module/listmaster/repository/list-master-items.repository.ts +173 -173
  182. package/src/module/listmaster/repository/list-master.repository.ts +46 -46
  183. package/src/module/listmaster/service/list-master-engine.ts +19 -19
  184. package/src/module/listmaster/service/list-master-extension.interface.ts +4 -4
  185. package/src/module/listmaster/service/list-master-item.service.ts +292 -292
  186. package/src/module/listmaster/service/list-master-registry.ts +15 -15
  187. package/src/module/listmaster/service/list-master.service.ts +544 -544
  188. package/src/module/mapper/controller/field-mapper.controller.ts +76 -76
  189. package/src/module/mapper/controller/mapper.controller.ts +20 -20
  190. package/src/module/mapper/dto/field-mapper.dto.ts +14 -14
  191. package/src/module/mapper/entity/field-lovs.entity.ts +19 -19
  192. package/src/module/mapper/entity/field-mapper.entity.ts +53 -53
  193. package/src/module/mapper/entity/mapper.entity.ts +16 -16
  194. package/src/module/mapper/mapper.module.ts +35 -35
  195. package/src/module/mapper/repository/field-lovs.repository.ts +35 -35
  196. package/src/module/mapper/repository/field-mapper.repository.ts +42 -42
  197. package/src/module/mapper/repository/mapper.repository.ts +32 -32
  198. package/src/module/mapper/service/field-mapper.service.ts +271 -271
  199. package/src/module/mapper/service/mapper.service.ts +81 -81
  200. package/src/module/master/controller/master.controller.ts +74 -74
  201. package/src/module/master/service/master.service.ts +483 -483
  202. package/src/module/meta/controller/app-master.controller.ts +38 -38
  203. package/src/module/meta/controller/attribute-master.controller.ts +84 -84
  204. package/src/module/meta/controller/entity-dynamic.controller.ts +125 -125
  205. package/src/module/meta/controller/entity-master.controller.ts +41 -41
  206. package/src/module/meta/controller/entity-relation.controller.ts +36 -36
  207. package/src/module/meta/controller/entity.controller.ts +392 -392
  208. package/src/module/meta/controller/entity.public.controller.ts +75 -75
  209. package/src/module/meta/controller/media.controller.ts +107 -107
  210. package/src/module/meta/controller/meta.controller.ts +96 -96
  211. package/src/module/meta/controller/view-master.controller.ts +86 -86
  212. package/src/module/meta/dto/entity-list-data.dto.ts +6 -6
  213. package/src/module/meta/dto/entity-tab.dto.ts +4 -4
  214. package/src/module/meta/dto/entity-table.dto.ts +9 -9
  215. package/src/module/meta/entity/app-master.entity.ts +34 -34
  216. package/src/module/meta/entity/attribute-master.entity.ts +92 -92
  217. package/src/module/meta/entity/base-entity.entity.ts +75 -75
  218. package/src/module/meta/entity/entity-master.entity.ts +85 -85
  219. package/src/module/meta/entity/entity-relation-data.entity.ts +29 -29
  220. package/src/module/meta/entity/entity-relation.entity.ts +23 -23
  221. package/src/module/meta/entity/entity-table-column.entity.ts +61 -61
  222. package/src/module/meta/entity/entity-table.entity.ts +50 -50
  223. package/src/module/meta/entity/media-data.entity.ts +32 -32
  224. package/src/module/meta/entity/preference.entity.ts +62 -62
  225. package/src/module/meta/entity/view-master.entity.ts +41 -41
  226. package/src/module/meta/entity.module.ts +166 -166
  227. package/src/module/meta/repository/app-master.repository.ts +20 -20
  228. package/src/module/meta/repository/attribute-master.repository.ts +138 -138
  229. package/src/module/meta/repository/entity-attribute-update.repository.ts +44 -44
  230. package/src/module/meta/repository/entity-master.repository.ts +111 -111
  231. package/src/module/meta/repository/entity-table-column.repository.ts +39 -39
  232. package/src/module/meta/repository/entity-table.repository.ts +53 -53
  233. package/src/module/meta/repository/media-data.repository.ts +50 -50
  234. package/src/module/meta/repository/preference.repository.ts +20 -20
  235. package/src/module/meta/repository/user-app-mapping.repository.ts +28 -28
  236. package/src/module/meta/repository/view-master.repository.ts +42 -42
  237. package/src/module/meta/service/app-master.service.ts +37 -37
  238. package/src/module/meta/service/attribute-master.service.ts +130 -130
  239. package/src/module/meta/service/common.service.ts +9 -9
  240. package/src/module/meta/service/entity-attribute-update.service.ts +28 -28
  241. package/src/module/meta/service/entity-dynamic.service.ts +809 -809
  242. package/src/module/meta/service/entity-list.service.ts +205 -205
  243. package/src/module/meta/service/entity-master.service.ts +171 -171
  244. package/src/module/meta/service/entity-realation-data.service.ts +9 -9
  245. package/src/module/meta/service/entity-relation.service.ts +87 -87
  246. package/src/module/meta/service/entity-service-impl.service.ts +525 -525
  247. package/src/module/meta/service/entity-table-column.service.ts +39 -39
  248. package/src/module/meta/service/entity-table.service.ts +150 -150
  249. package/src/module/meta/service/entity-validation.service.ts +187 -187
  250. package/src/module/meta/service/entity.service.ts +67 -67
  251. package/src/module/meta/service/field-group.service.ts +103 -103
  252. package/src/module/meta/service/media-data.service.ts +507 -507
  253. package/src/module/meta/service/populate-meta.service.ts +222 -222
  254. package/src/module/meta/service/preference.service.ts +16 -16
  255. package/src/module/meta/service/resolver.service.ts +271 -271
  256. package/src/module/meta/service/section-master.service.ts +104 -104
  257. package/src/module/meta/service/update-form-json.service.ts +22 -22
  258. package/src/module/meta/service/user-app-mapping.service.ts +17 -17
  259. package/src/module/meta/service/view-master.service.ts +127 -127
  260. package/src/module/microservice-client/microservice-clients.module.ts +13 -13
  261. package/src/module/microservice-client/service/microservice-client-factory.ts +37 -37
  262. package/src/module/microservice-client/service/microservice-clients.ts +4 -4
  263. package/src/module/module/controller/menu.controller.ts +15 -15
  264. package/src/module/module/controller/module-access.controller.ts +134 -134
  265. package/src/module/module/entity/menu.entity.ts +43 -43
  266. package/src/module/module/entity/module-access.entity.ts +25 -25
  267. package/src/module/module/entity/module-action.entity.ts +17 -17
  268. package/src/module/module/entity/module.entity.ts +52 -52
  269. package/src/module/module/module.module.ts +42 -42
  270. package/src/module/module/repository/menu.repository.ts +191 -191
  271. package/src/module/module/repository/module-access.repository.ts +344 -344
  272. package/src/module/module/service/menu.service.ts +82 -82
  273. package/src/module/module/service/module-access.service.ts +195 -195
  274. package/src/module/notification/controller/notification.controller.ts +58 -58
  275. package/src/module/notification/controller/otp.controller.ts +117 -117
  276. package/src/module/notification/entity/notification.entity.ts +26 -26
  277. package/src/module/notification/entity/otp.entity.ts +28 -28
  278. package/src/module/notification/firebase-admin.config.ts +22 -22
  279. package/src/module/notification/notification.module.ts +69 -69
  280. package/src/module/notification/repository/otp.repository.ts +27 -27
  281. package/src/module/notification/service/email.service.ts +127 -127
  282. package/src/module/notification/service/notification.service.ts +160 -160
  283. package/src/module/notification/service/otp.service.ts +133 -133
  284. package/src/module/third-party-module/entity/third-party-api-registry.entity.ts +52 -52
  285. package/src/module/third-party-module/repository/third-party-api-registry.repository.ts +20 -20
  286. package/src/module/third-party-module/service/api-registry.service.ts +13 -13
  287. package/src/module/third-party-module/third-party.module.ts +12 -12
  288. package/src/module/user/controller/login.controller.ts +198 -198
  289. package/src/module/user/controller/user.controller.ts +40 -40
  290. package/src/module/user/dto/create-user.dto.ts +62 -62
  291. package/src/module/user/dto/update-user.dto.ts +4 -4
  292. package/src/module/user/entity/role.entity.ts +33 -33
  293. package/src/module/user/entity/user-role-mapping.entity.ts +38 -38
  294. package/src/module/user/entity/user-session.entity.ts +73 -73
  295. package/src/module/user/entity/user.entity.ts +59 -59
  296. package/src/module/user/repository/role.repository.ts +96 -96
  297. package/src/module/user/repository/user-role-mapping.repository.ts +126 -126
  298. package/src/module/user/repository/user.repository.ts +50 -50
  299. package/src/module/user/repository/userSession.repository.ts +33 -33
  300. package/src/module/user/service/login.service.ts +326 -326
  301. package/src/module/user/service/role.service.ts +189 -189
  302. package/src/module/user/service/user-role-mapping.service.ts +98 -98
  303. package/src/module/user/service/user-session.service.ts +168 -168
  304. package/src/module/user/service/user.service.ts +368 -368
  305. package/src/module/user/user.module.ts +65 -65
  306. package/src/module/workflow/controller/action-category.controller.ts +54 -54
  307. package/src/module/workflow/controller/action-resource-mapping.controller.ts +23 -23
  308. package/src/module/workflow/controller/action-template-mapping.controller.ts +35 -35
  309. package/src/module/workflow/controller/action.controller.ts +111 -111
  310. package/src/module/workflow/controller/activity-log.controller.ts +55 -55
  311. package/src/module/workflow/controller/comm-template.controller.ts +43 -43
  312. package/src/module/workflow/controller/entity-modification.controller.ts +35 -35
  313. package/src/module/workflow/controller/form-master.controller.ts +43 -43
  314. package/src/module/workflow/controller/stage-group.controller.ts +48 -48
  315. package/src/module/workflow/controller/stage.controller.ts +50 -50
  316. package/src/module/workflow/controller/task.controller.ts +77 -77
  317. package/src/module/workflow/controller/workflow-list-master.controller.ts +44 -44
  318. package/src/module/workflow/controller/workflow-meta.controller.ts +80 -80
  319. package/src/module/workflow/controller/workflow.controller.ts +67 -67
  320. package/src/module/workflow/entity/action-category.entity.ts +38 -38
  321. package/src/module/workflow/entity/action-data.entity.ts +55 -55
  322. package/src/module/workflow/entity/action-resources-mapping.entity.ts +29 -29
  323. package/src/module/workflow/entity/action-template-mapping.entity.ts +17 -17
  324. package/src/module/workflow/entity/action.entity.ts +53 -53
  325. package/src/module/workflow/entity/activity-log.entity.ts +43 -43
  326. package/src/module/workflow/entity/comm-template.entity.ts +43 -43
  327. package/src/module/workflow/entity/entity-modification.entity.ts +38 -38
  328. package/src/module/workflow/entity/form.entity.ts +25 -25
  329. package/src/module/workflow/entity/stage-action-mapping.entity.ts +17 -17
  330. package/src/module/workflow/entity/stage-group.entity.ts +23 -23
  331. package/src/module/workflow/entity/stage-movement-data.entity.ts +38 -38
  332. package/src/module/workflow/entity/stage.entity.ts +20 -20
  333. package/src/module/workflow/entity/task-data.entity.ts +88 -88
  334. package/src/module/workflow/entity/template-attach-mapper.entity.ts +30 -30
  335. package/src/module/workflow/entity/workflow-data.entity.ts +11 -11
  336. package/src/module/workflow/entity/workflow-level-mapping.entity.ts +18 -18
  337. package/src/module/workflow/entity/workflow.entity.ts +20 -20
  338. package/src/module/workflow/repository/action-category.repository.ts +79 -79
  339. package/src/module/workflow/repository/action-data.repository.ts +334 -334
  340. package/src/module/workflow/repository/action.repository.ts +324 -324
  341. package/src/module/workflow/repository/activity-log.repository.ts +148 -148
  342. package/src/module/workflow/repository/comm-template.repository.ts +149 -149
  343. package/src/module/workflow/repository/form-master.repository.ts +59 -59
  344. package/src/module/workflow/repository/stage-group.repository.ts +197 -197
  345. package/src/module/workflow/repository/stage-movement.repository.ts +246 -246
  346. package/src/module/workflow/repository/stage.repository.ts +172 -172
  347. package/src/module/workflow/repository/task.repository.ts +134 -134
  348. package/src/module/workflow/repository/workflow.repository.ts +42 -42
  349. package/src/module/workflow/service/action-category.service.ts +33 -33
  350. package/src/module/workflow/service/action-data.service.ts +62 -62
  351. package/src/module/workflow/service/action-resources-mapping.service.ts +10 -10
  352. package/src/module/workflow/service/action-template-mapping.service.ts +131 -131
  353. package/src/module/workflow/service/action.service.ts +279 -279
  354. package/src/module/workflow/service/activity-log.service.ts +107 -107
  355. package/src/module/workflow/service/comm-template.service.ts +180 -180
  356. package/src/module/workflow/service/entity-modification.service.ts +61 -61
  357. package/src/module/workflow/service/form-master.service.ts +35 -35
  358. package/src/module/workflow/service/populate-workflow.service.ts +330 -330
  359. package/src/module/workflow/service/stage-action-mapping.service.ts +5 -5
  360. package/src/module/workflow/service/stage-group.service.ts +342 -342
  361. package/src/module/workflow/service/stage.service.ts +199 -199
  362. package/src/module/workflow/service/task.service.ts +558 -558
  363. package/src/module/workflow/service/workflow-list-master.service.ts +60 -60
  364. package/src/module/workflow/service/workflow-meta.service.ts +654 -654
  365. package/src/module/workflow/service/workflow.service.ts +205 -205
  366. package/src/module/workflow/workflow.module.ts +180 -180
  367. package/src/module/workflow-automation/SCHEDULING_GUIDE.md +145 -145
  368. package/src/module/workflow-automation/controller/workflow-automation.controller.ts +43 -43
  369. package/src/module/workflow-automation/entity/workflow-automation-action.entity.ts +26 -26
  370. package/src/module/workflow-automation/entity/workflow-automation.entity.ts +40 -40
  371. package/src/module/workflow-automation/interface/action.decorator.ts +7 -7
  372. package/src/module/workflow-automation/interface/action.interface.ts +5 -5
  373. package/src/module/workflow-automation/service/action-registery.service.ts +35 -35
  374. package/src/module/workflow-automation/service/schedule-handler.service.ts +168 -168
  375. package/src/module/workflow-automation/service/workflow-automation-engine.service.ts +224 -224
  376. package/src/module/workflow-automation/service/workflow-automation.service.ts +515 -515
  377. package/src/module/workflow-automation/workflow-automation.module.ts +54 -54
  378. package/src/module/workflow-schedule/INSTALLATION.md +244 -244
  379. package/src/module/workflow-schedule/MULTI_PROJECT_GUIDE.md +196 -196
  380. package/src/module/workflow-schedule/README.md +422 -422
  381. package/src/module/workflow-schedule/constants/schedule.constants.ts +48 -48
  382. package/src/module/workflow-schedule/controller/workflow-schedule.controller.ts +255 -255
  383. package/src/module/workflow-schedule/docs/CLAUDE_CODE_GUIDE.md +510 -510
  384. package/src/module/workflow-schedule/docs/CLAUDE_CODE_PROMPT.md +362 -362
  385. package/src/module/workflow-schedule/docs/RUN_CLAUDE_CODE.sh +68 -68
  386. package/src/module/workflow-schedule/dto/create-schedule.dto.ts +147 -147
  387. package/src/module/workflow-schedule/dto/get-execution-logs.dto.ts +119 -119
  388. package/src/module/workflow-schedule/dto/update-schedule.dto.ts +96 -96
  389. package/src/module/workflow-schedule/entities/scheduled-workflow.entity.ts +148 -148
  390. package/src/module/workflow-schedule/entities/workflow-execution-log.entity.ts +154 -154
  391. package/src/module/workflow-schedule/interfaces/schedule-job-data.interface.ts +53 -53
  392. package/src/module/workflow-schedule/interfaces/workflow-schedule-options.interface.ts +12 -12
  393. package/src/module/workflow-schedule/processors/schedule.processor.ts +584 -584
  394. package/src/module/workflow-schedule/service/workflow-schedule.service.ts +600 -600
  395. package/src/module/workflow-schedule/workflow-schedule.module.ts +67 -67
  396. package/src/resources/dev.properties.yaml +31 -31
  397. package/src/resources/local.properties.yaml +27 -27
  398. package/src/resources/properties.module.ts +12 -12
  399. package/src/resources/properties.yaml.ts +11 -11
  400. package/src/resources/uat.properties.yaml +31 -31
  401. package/src/table.config.ts +133 -133
  402. package/src/utils/dto/excel-data.dto.ts +14 -14
  403. package/src/utils/dto/excelsheet-data.dto.ts +5 -5
  404. package/src/utils/service/base64util.service.ts +18 -18
  405. package/src/utils/service/clockIDGenUtil.service.ts +21 -21
  406. package/src/utils/service/codeGenerator.service.ts +22 -22
  407. package/src/utils/service/dateUtil.service.ts +17 -17
  408. package/src/utils/service/encryptUtil.service.ts +97 -97
  409. package/src/utils/service/excel-helper.service.ts +72 -72
  410. package/src/utils/service/excelUtil.service.ts +15 -15
  411. package/src/utils/service/file-util.service.ts +11 -11
  412. package/src/utils/service/json-util.service.ts +23 -23
  413. package/src/utils/service/loggingUtil.service.ts +88 -88
  414. package/src/utils/service/reflection-helper.service.ts +62 -62
  415. package/src/utils/service/wbsCodeGen.service.ts +8 -8
  416. package/src/utils/utils.module.ts +27 -27
  417. package/tsconfig.build.json +4 -4
  418. package/tsconfig.json +24 -24
  419. package/.claude/settings.local.json +0 -26
  420. package/.idea/copilot.data.migration.agent.xml +0 -6
  421. package/.idea/copilot.data.migration.ask.xml +0 -6
  422. package/.idea/copilot.data.migration.ask2agent.xml +0 -6
  423. package/.idea/copilot.data.migration.edit.xml +0 -6
  424. package/.idea/misc.xml +0 -6
  425. package/server.log +0 -850
@@ -1,600 +1,600 @@
1
- import { Injectable, Logger, NotFoundException, BadRequestException } from '@nestjs/common';
2
- import { InjectRepository } from '@nestjs/typeorm';
3
- import { Repository, DataSource, Between, In } from 'typeorm';
4
- import { InjectQueue } from '@nestjs/bull';
5
- import { Queue } from 'bull';
6
- import * as cronParser from 'cron-parser';
7
-
8
- import { ScheduledWorkflow } from '../entities/scheduled-workflow.entity';
9
- import { WorkflowExecutionLog } from '../entities/workflow-execution-log.entity';
10
- import { CreateScheduleDto } from '../dto/create-schedule.dto';
11
- import { UpdateScheduleDto } from '../dto/update-schedule.dto';
12
- import { GetExecutionLogsDto } from '../dto/get-execution-logs.dto';
13
- import { UserData } from '../../user/entity/user.entity';
14
- import {
15
- WORKFLOW_SCHEDULE_QUEUE,
16
- EXECUTE_SCHEDULED_WORKFLOW_JOB,
17
- SCHEDULE_STATUS_ACTIVE,
18
- SCHEDULE_STATUS_PAUSED,
19
- SCHEDULE_STATUS_INACTIVE,
20
- DEFAULT_MAX_RETRIES,
21
- DEFAULT_RETRY_DELAY,
22
- DEFAULT_BACKOFF_MULTIPLIER,
23
- DEFAULT_TIMEZONE,
24
- } from '../constants/schedule.constants';
25
- import { ScheduleJobData } from '../interfaces/schedule-job-data.interface';
26
-
27
- /**
28
- * Workflow Schedule Service
29
- * Manages scheduled workflows and their execution
30
- */
31
- @Injectable()
32
- export class WorkflowScheduleService {
33
- private readonly logger = new Logger(WorkflowScheduleService.name);
34
-
35
- constructor(
36
- @InjectRepository(ScheduledWorkflow)
37
- private readonly scheduledWorkflowRepository: Repository<ScheduledWorkflow>,
38
- @InjectRepository(WorkflowExecutionLog)
39
- private readonly executionLogRepository: Repository<WorkflowExecutionLog>,
40
- @InjectQueue(WORKFLOW_SCHEDULE_QUEUE)
41
- private readonly scheduleQueue: Queue<ScheduleJobData>,
42
- private readonly dataSource: DataSource,
43
- ) {}
44
-
45
- /**
46
- * 1. Create a new scheduled workflow
47
- */
48
- async createSchedule(
49
- createScheduleDto: CreateScheduleDto,
50
- loggedInUser: UserData,
51
- ): Promise<ScheduledWorkflow> {
52
- this.logger.log(
53
- `Creating schedule for workflow ${createScheduleDto.workflow_id} by user ${loggedInUser.id}`,
54
- );
55
-
56
- try {
57
- // Validate cron expression
58
- this.validateCronExpression(createScheduleDto.cron_expression, createScheduleDto.timezone);
59
-
60
- // Calculate next execution time
61
- const nextExecutionAt = this.calculateNextExecution(
62
- createScheduleDto.cron_expression,
63
- createScheduleDto.timezone || DEFAULT_TIMEZONE,
64
- );
65
-
66
- // Create scheduled workflow entity
67
- const schedule = this.scheduledWorkflowRepository.create({
68
- workflow_id: createScheduleDto.workflow_id,
69
- workflow_name: createScheduleDto.workflow_name,
70
- name: createScheduleDto.name,
71
- description: createScheduleDto.description,
72
- cron_expression: createScheduleDto.cron_expression,
73
- timezone: createScheduleDto.timezone || DEFAULT_TIMEZONE,
74
- start_date: createScheduleDto.start_date ? new Date(createScheduleDto.start_date) : null,
75
- end_date: createScheduleDto.end_date ? new Date(createScheduleDto.end_date) : null,
76
- max_executions: createScheduleDto.max_executions,
77
- execution_count: 0,
78
- next_execution_at: nextExecutionAt,
79
- schedule_status: SCHEDULE_STATUS_ACTIVE,
80
- retry_config: createScheduleDto.retry_config || {
81
- maxRetries: DEFAULT_MAX_RETRIES,
82
- retryDelay: DEFAULT_RETRY_DELAY,
83
- backoffMultiplier: DEFAULT_BACKOFF_MULTIPLIER,
84
- },
85
- metadata: createScheduleDto.metadata || {},
86
- is_enabled: createScheduleDto.is_enabled !== false,
87
- organization_id: createScheduleDto.organization_id || loggedInUser.organization_id,
88
- enterprise_id: createScheduleDto.enterprise_id || loggedInUser.enterprise_id,
89
- level_id: createScheduleDto.level_id || loggedInUser.level_id,
90
- level_type: createScheduleDto.level_type || loggedInUser.level_type,
91
- appcode: createScheduleDto.appcode || loggedInUser.appcode,
92
- created_by: loggedInUser.id,
93
- created_date: new Date(),
94
- status: createScheduleDto.status || 'ACTIVE',
95
- entity_type: 'WFSC',
96
- });
97
-
98
- const savedSchedule = await this.scheduledWorkflowRepository.save(schedule);
99
-
100
- // Add job to Bull queue with cron schedule
101
- if (savedSchedule.is_enabled && savedSchedule.schedule_status === SCHEDULE_STATUS_ACTIVE) {
102
- await this.scheduleJob(savedSchedule, loggedInUser);
103
- }
104
-
105
- this.logger.log(`Schedule created successfully with ID: ${savedSchedule.id}`);
106
- return savedSchedule;
107
- } catch (error) {
108
- this.logger.error(`Failed to create schedule: ${error.message}`, error.stack);
109
- throw error;
110
- }
111
- }
112
-
113
- /**
114
- * 2. Update an existing scheduled workflow
115
- */
116
- async updateSchedule(
117
- updateScheduleDto: UpdateScheduleDto,
118
- loggedInUser: UserData,
119
- ): Promise<ScheduledWorkflow> {
120
- this.logger.log(`Updating schedule ${updateScheduleDto.id} by user ${loggedInUser.id}`);
121
-
122
- try {
123
- const schedule = await this.scheduledWorkflowRepository.findOne({
124
- where: { id: updateScheduleDto.id },
125
- });
126
-
127
- if (!schedule) {
128
- throw new NotFoundException(`Scheduled workflow not found with ID: ${updateScheduleDto.id}`);
129
- }
130
-
131
- // Validate cron expression if updated
132
- if (updateScheduleDto.cron_expression) {
133
- this.validateCronExpression(
134
- updateScheduleDto.cron_expression,
135
- updateScheduleDto.timezone || schedule.timezone,
136
- );
137
- }
138
-
139
- // Update fields
140
- if (updateScheduleDto.workflow_id !== undefined) {
141
- schedule.workflow_id = updateScheduleDto.workflow_id;
142
- }
143
- if (updateScheduleDto.workflow_name !== undefined) {
144
- schedule.workflow_name = updateScheduleDto.workflow_name;
145
- }
146
- if (updateScheduleDto.name !== undefined) {
147
- schedule.name = updateScheduleDto.name;
148
- }
149
- if (updateScheduleDto.description !== undefined) {
150
- schedule.description = updateScheduleDto.description;
151
- }
152
- if (updateScheduleDto.cron_expression !== undefined) {
153
- schedule.cron_expression = updateScheduleDto.cron_expression;
154
- schedule.next_execution_at = this.calculateNextExecution(
155
- updateScheduleDto.cron_expression,
156
- updateScheduleDto.timezone || schedule.timezone,
157
- );
158
- }
159
- if (updateScheduleDto.timezone !== undefined) {
160
- schedule.timezone = updateScheduleDto.timezone;
161
- }
162
- if (updateScheduleDto.start_date !== undefined) {
163
- schedule.start_date = updateScheduleDto.start_date
164
- ? new Date(updateScheduleDto.start_date)
165
- : null;
166
- }
167
- if (updateScheduleDto.end_date !== undefined) {
168
- schedule.end_date = updateScheduleDto.end_date ? new Date(updateScheduleDto.end_date) : null;
169
- }
170
- if (updateScheduleDto.max_executions !== undefined) {
171
- schedule.max_executions = updateScheduleDto.max_executions;
172
- }
173
- if (updateScheduleDto.schedule_status !== undefined) {
174
- schedule.schedule_status = updateScheduleDto.schedule_status;
175
- }
176
- if (updateScheduleDto.retry_config !== undefined) {
177
- schedule.retry_config = updateScheduleDto.retry_config;
178
- }
179
- if (updateScheduleDto.actions !== undefined) {
180
- schedule.actions = updateScheduleDto.actions;
181
- }
182
- if (updateScheduleDto.metadata !== undefined) {
183
- schedule.metadata = updateScheduleDto.metadata;
184
- }
185
- if (updateScheduleDto.is_enabled !== undefined) {
186
- schedule.is_enabled = updateScheduleDto.is_enabled;
187
- }
188
- if (updateScheduleDto.status !== undefined) {
189
- schedule.status = updateScheduleDto.status;
190
- }
191
-
192
- schedule.modified_by = loggedInUser.id;
193
- schedule.modified_date = new Date();
194
-
195
- const updatedSchedule = await this.scheduledWorkflowRepository.save(schedule);
196
-
197
- // Remove old job and create new one if schedule changed
198
- if (schedule.job_id) {
199
- await this.removeJob(schedule.job_id);
200
- }
201
-
202
- if (updatedSchedule.is_enabled && updatedSchedule.schedule_status === SCHEDULE_STATUS_ACTIVE) {
203
- await this.scheduleJob(updatedSchedule, loggedInUser);
204
- }
205
-
206
- this.logger.log(`Schedule updated successfully: ${updatedSchedule.id}`);
207
- return updatedSchedule;
208
- } catch (error) {
209
- this.logger.error(`Failed to update schedule: ${error.message}`, error.stack);
210
- throw error;
211
- }
212
- }
213
-
214
- /**
215
- * 3. Get a scheduled workflow by ID
216
- */
217
- async getScheduleById(scheduleId: number, loggedInUser: UserData): Promise<ScheduledWorkflow> {
218
- const schedule = await this.scheduledWorkflowRepository.findOne({
219
- where: {
220
- id: scheduleId,
221
- organization_id: loggedInUser.organization_id,
222
- },
223
- });
224
-
225
- if (!schedule) {
226
- throw new NotFoundException(`Scheduled workflow not found with ID: ${scheduleId}`);
227
- }
228
-
229
- return schedule;
230
- }
231
-
232
- /**
233
- * 4. Get all scheduled workflows with pagination and filters
234
- */
235
- async getAllSchedules(
236
- page: number = 1,
237
- size: number = 10,
238
- filters: any = {},
239
- loggedInUser: UserData,
240
- ): Promise<{ data: ScheduledWorkflow[]; total: number; page: number; size: number }> {
241
- const skip = (page - 1) * size;
242
-
243
- const whereConditions: any = {
244
- organization_id: loggedInUser.organization_id,
245
- };
246
-
247
- if (filters.workflow_id) {
248
- whereConditions.workflow_id = filters.workflow_id;
249
- }
250
- if (filters.schedule_status) {
251
- whereConditions.schedule_status = filters.schedule_status;
252
- }
253
- if (filters.is_enabled !== undefined) {
254
- whereConditions.is_enabled = filters.is_enabled;
255
- }
256
-
257
- const [data, total] = await this.scheduledWorkflowRepository.findAndCount({
258
- where: whereConditions,
259
- skip,
260
- take: size,
261
- order: { created_date: 'DESC' },
262
- });
263
-
264
- return {
265
- data,
266
- total,
267
- page,
268
- size,
269
- };
270
- }
271
-
272
- /**
273
- * 5. Pause a scheduled workflow
274
- */
275
- async pauseSchedule(scheduleId: number, loggedInUser: UserData): Promise<ScheduledWorkflow> {
276
- this.logger.log(`Pausing schedule ${scheduleId} by user ${loggedInUser.id}`);
277
-
278
- const schedule = await this.getScheduleById(scheduleId, loggedInUser);
279
-
280
- if (schedule.schedule_status === SCHEDULE_STATUS_PAUSED) {
281
- throw new BadRequestException('Schedule is already paused');
282
- }
283
-
284
- schedule.schedule_status = SCHEDULE_STATUS_PAUSED;
285
- schedule.modified_by = loggedInUser.id;
286
- schedule.modified_date = new Date();
287
-
288
- const updatedSchedule = await this.scheduledWorkflowRepository.save(schedule);
289
-
290
- // Remove job from queue
291
- if (schedule.job_id) {
292
- await this.removeJob(schedule.job_id);
293
- updatedSchedule.job_id = null;
294
- await this.scheduledWorkflowRepository.save(updatedSchedule);
295
- }
296
-
297
- this.logger.log(`Schedule paused successfully: ${scheduleId}`);
298
- return updatedSchedule;
299
- }
300
-
301
- /**
302
- * 6. Resume a paused scheduled workflow
303
- */
304
- async resumeSchedule(scheduleId: number, loggedInUser: UserData): Promise<ScheduledWorkflow> {
305
- this.logger.log(`Resuming schedule ${scheduleId} by user ${loggedInUser.id}`);
306
-
307
- const schedule = await this.getScheduleById(scheduleId, loggedInUser);
308
-
309
- if (schedule.schedule_status !== SCHEDULE_STATUS_PAUSED) {
310
- throw new BadRequestException('Schedule is not paused');
311
- }
312
-
313
- schedule.schedule_status = SCHEDULE_STATUS_ACTIVE;
314
- schedule.modified_by = loggedInUser.id;
315
- schedule.modified_date = new Date();
316
-
317
- // Recalculate next execution time
318
- schedule.next_execution_at = this.calculateNextExecution(
319
- schedule.cron_expression,
320
- schedule.timezone,
321
- );
322
-
323
- const updatedSchedule = await this.scheduledWorkflowRepository.save(schedule);
324
-
325
- // Re-add job to queue
326
- if (updatedSchedule.is_enabled) {
327
- await this.scheduleJob(updatedSchedule, loggedInUser);
328
- }
329
-
330
- this.logger.log(`Schedule resumed successfully: ${scheduleId}`);
331
- return updatedSchedule;
332
- }
333
-
334
- /**
335
- * 7. Delete a scheduled workflow
336
- */
337
- async deleteSchedule(scheduleId: number, loggedInUser: UserData): Promise<void> {
338
- this.logger.log(`Deleting schedule ${scheduleId} by user ${loggedInUser.id}`);
339
-
340
- const schedule = await this.getScheduleById(scheduleId, loggedInUser);
341
-
342
- // Remove job from queue
343
- if (schedule.job_id) {
344
- await this.removeJob(schedule.job_id);
345
- }
346
-
347
- // Soft delete by setting status to inactive
348
- schedule.schedule_status = SCHEDULE_STATUS_INACTIVE;
349
- schedule.status = 'INACTIVE';
350
- schedule.is_enabled = false;
351
- schedule.modified_by = loggedInUser.id;
352
- schedule.modified_date = new Date();
353
-
354
- await this.scheduledWorkflowRepository.save(schedule);
355
-
356
- this.logger.log(`Schedule deleted successfully: ${scheduleId}`);
357
- }
358
-
359
- /**
360
- * 8. Manually trigger a scheduled workflow execution
361
- */
362
- async triggerManualExecution(
363
- scheduleId: number,
364
- loggedInUser: UserData,
365
- metadata?: Record<string, any>,
366
- ): Promise<{ executionLogId: number; jobId: string }> {
367
- this.logger.log(`Manual trigger for schedule ${scheduleId} by user ${loggedInUser.id}`);
368
-
369
- const schedule = await this.getScheduleById(scheduleId, loggedInUser);
370
-
371
- const jobData: ScheduleJobData = {
372
- scheduleId: schedule.id,
373
- workflowId: schedule.workflow_id,
374
- workflowName: schedule.workflow_name,
375
- organizationId: schedule.organization_id,
376
- enterpriseId: schedule.enterprise_id,
377
- levelId: schedule.level_id,
378
- levelType: schedule.level_type,
379
- appcode: schedule.appcode,
380
- createdBy: loggedInUser.id,
381
- triggeredBy: 'MANUAL',
382
- triggeredAt: new Date(),
383
- metadata: metadata || {},
384
- };
385
-
386
- // Add job to queue immediately (not scheduled)
387
- const job = await this.scheduleQueue.add(EXECUTE_SCHEDULED_WORKFLOW_JOB, jobData, {
388
- attempts: schedule.retry_config?.maxRetries || DEFAULT_MAX_RETRIES,
389
- backoff: {
390
- type: 'exponential',
391
- delay: schedule.retry_config?.retryDelay || DEFAULT_RETRY_DELAY,
392
- },
393
- });
394
-
395
- // Create execution log entry
396
- const executionLog = this.executionLogRepository.create({
397
- schedule_id: schedule.id,
398
- workflow_id: schedule.workflow_id,
399
- job_id: job.id.toString(),
400
- execution_status: 'PENDING',
401
- triggered_by: 'MANUAL',
402
- triggered_by_user_id: loggedInUser.id,
403
- organization_id: schedule.organization_id,
404
- enterprise_id: schedule.enterprise_id,
405
- created_by: loggedInUser.id,
406
- created_date: new Date(),
407
- entity_type: 'WFEL',
408
- status: 'ACTIVE',
409
- });
410
-
411
- const savedLog = await this.executionLogRepository.save(executionLog);
412
-
413
- this.logger.log(`Manual execution triggered for schedule ${scheduleId}, job ID: ${job.id}`);
414
-
415
- return {
416
- executionLogId: savedLog.id,
417
- jobId: job.id.toString(),
418
- };
419
- }
420
-
421
- /**
422
- * 9. Get execution logs with filters and pagination
423
- */
424
- async getExecutionLogs(
425
- getExecutionLogsDto: GetExecutionLogsDto,
426
- loggedInUser: UserData,
427
- ): Promise<{ data: WorkflowExecutionLog[]; total: number; page: number; size: number }> {
428
- const page = getExecutionLogsDto.page || 1;
429
- const size = getExecutionLogsDto.size || 10;
430
- const skip = (page - 1) * size;
431
-
432
- const whereConditions: any = {
433
- organization_id: getExecutionLogsDto.organization_id || loggedInUser.organization_id,
434
- };
435
-
436
- if (getExecutionLogsDto.schedule_id) {
437
- whereConditions.schedule_id = getExecutionLogsDto.schedule_id;
438
- }
439
- if (getExecutionLogsDto.workflow_id) {
440
- whereConditions.workflow_id = getExecutionLogsDto.workflow_id;
441
- }
442
- if (getExecutionLogsDto.execution_status) {
443
- whereConditions.execution_status = getExecutionLogsDto.execution_status;
444
- }
445
- if (getExecutionLogsDto.execution_statuses && getExecutionLogsDto.execution_statuses.length > 0) {
446
- whereConditions.execution_status = In(getExecutionLogsDto.execution_statuses);
447
- }
448
- if (getExecutionLogsDto.triggered_by) {
449
- whereConditions.triggered_by = getExecutionLogsDto.triggered_by;
450
- }
451
- if (getExecutionLogsDto.triggered_by_user_id) {
452
- whereConditions.triggered_by_user_id = getExecutionLogsDto.triggered_by_user_id;
453
- }
454
-
455
- // Date range filter
456
- if (getExecutionLogsDto.start_date && getExecutionLogsDto.end_date) {
457
- whereConditions.created_date = Between(
458
- new Date(getExecutionLogsDto.start_date),
459
- new Date(getExecutionLogsDto.end_date),
460
- );
461
- }
462
-
463
- const [data, total] = await this.executionLogRepository.findAndCount({
464
- where: whereConditions,
465
- skip,
466
- take: size,
467
- order: {
468
- [getExecutionLogsDto.sortBy || 'created_date']:
469
- getExecutionLogsDto.sortOrder || 'DESC',
470
- },
471
- });
472
-
473
- return {
474
- data,
475
- total,
476
- page,
477
- size,
478
- };
479
- }
480
-
481
- /**
482
- * Get execution statistics for a schedule
483
- */
484
- async getExecutionStats(scheduleId: number, loggedInUser: UserData): Promise<any> {
485
- const schedule = await this.getScheduleById(scheduleId, loggedInUser);
486
-
487
- const stats = await this.dataSource.query(
488
- `SELECT
489
- COUNT(*) as total_executions,
490
- SUM(CASE WHEN execution_status = 'COMPLETED' THEN 1 ELSE 0 END) as successful_executions,
491
- SUM(CASE WHEN execution_status = 'FAILED' THEN 1 ELSE 0 END) as failed_executions,
492
- SUM(CASE WHEN execution_status = 'PENDING' THEN 1 ELSE 0 END) as pending_executions,
493
- SUM(CASE WHEN execution_status = 'RUNNING' THEN 1 ELSE 0 END) as running_executions,
494
- AVG(duration_ms) as average_duration_ms,
495
- SUM(total_records) as total_records_processed
496
- FROM cr_wf_execution_log
497
- WHERE schedule_id = ?`,
498
- [scheduleId],
499
- );
500
-
501
- const result = stats[0];
502
- const successRate =
503
- result.total_executions > 0
504
- ? (result.successful_executions / result.total_executions) * 100
505
- : 0;
506
-
507
- return {
508
- schedule_id: scheduleId,
509
- schedule_name: schedule.name,
510
- total_executions: parseInt(result.total_executions),
511
- successful_executions: parseInt(result.successful_executions),
512
- failed_executions: parseInt(result.failed_executions),
513
- pending_executions: parseInt(result.pending_executions),
514
- running_executions: parseInt(result.running_executions),
515
- average_duration_ms: parseFloat(result.average_duration_ms) || 0,
516
- total_records_processed: parseInt(result.total_records_processed) || 0,
517
- success_rate_percentage: parseFloat(successRate.toFixed(2)),
518
- };
519
- }
520
-
521
- /**
522
- * Private helper: Schedule a job in Bull queue
523
- */
524
- private async scheduleJob(schedule: ScheduledWorkflow, loggedInUser: UserData): Promise<void> {
525
- const jobData: ScheduleJobData = {
526
- scheduleId: schedule.id,
527
- workflowId: schedule.workflow_id,
528
- workflowName: schedule.workflow_name,
529
- organizationId: schedule.organization_id,
530
- enterpriseId: schedule.enterprise_id,
531
- levelId: schedule.level_id,
532
- levelType: schedule.level_type,
533
- appcode: schedule.appcode,
534
- createdBy: loggedInUser.id,
535
- triggeredBy: 'SCHEDULE',
536
- triggeredAt: new Date(),
537
- metadata: schedule.metadata || {},
538
- };
539
-
540
- const job = await this.scheduleQueue.add(EXECUTE_SCHEDULED_WORKFLOW_JOB, jobData, {
541
- repeat: {
542
- cron: schedule.cron_expression,
543
- tz: schedule.timezone,
544
- startDate: schedule.start_date || undefined,
545
- endDate: schedule.end_date || undefined,
546
- },
547
- attempts: schedule.retry_config?.maxRetries || DEFAULT_MAX_RETRIES,
548
- backoff: {
549
- type: 'exponential',
550
- delay: schedule.retry_config?.retryDelay || DEFAULT_RETRY_DELAY,
551
- },
552
- });
553
-
554
- schedule.job_id = job.id.toString();
555
- await this.scheduledWorkflowRepository.save(schedule);
556
-
557
- this.logger.log(`Job scheduled with ID: ${job.id} for schedule ${schedule.id}`);
558
- }
559
-
560
- /**
561
- * Private helper: Remove a job from Bull queue
562
- */
563
- private async removeJob(jobId: string): Promise<void> {
564
- try {
565
- const job = await this.scheduleQueue.getJob(jobId);
566
- if (job) {
567
- await job.remove();
568
- this.logger.log(`Job removed: ${jobId}`);
569
- }
570
- } catch (error) {
571
- this.logger.warn(`Failed to remove job ${jobId}: ${error.message}`);
572
- }
573
- }
574
-
575
- /**
576
- * Private helper: Validate cron expression
577
- */
578
- private validateCronExpression(cronExpression: string, timezone: string): void {
579
- try {
580
- cronParser.CronExpressionParser.parse(cronExpression, { tz: timezone });
581
- } catch (error: any) {
582
- throw new BadRequestException(
583
- `Invalid cron expression: ${cronExpression}. Error: ${error.message}`,
584
- );
585
- }
586
- }
587
-
588
- /**
589
- * Private helper: Calculate next execution time
590
- */
591
- private calculateNextExecution(cronExpression: string, timezone: string): Date | null {
592
- try {
593
- const interval = cronParser.CronExpressionParser.parse(cronExpression, { tz: timezone });
594
- return interval.next().toDate();
595
- } catch (error: any) {
596
- this.logger.error(`Failed to calculate next execution: ${error.message}`);
597
- return null;
598
- }
599
- }
600
- }
1
+ import { Injectable, Logger, NotFoundException, BadRequestException } from '@nestjs/common';
2
+ import { InjectRepository } from '@nestjs/typeorm';
3
+ import { Repository, DataSource, Between, In } from 'typeorm';
4
+ import { InjectQueue } from '@nestjs/bull';
5
+ import { Queue } from 'bull';
6
+ import * as cronParser from 'cron-parser';
7
+
8
+ import { ScheduledWorkflow } from '../entities/scheduled-workflow.entity';
9
+ import { WorkflowExecutionLog } from '../entities/workflow-execution-log.entity';
10
+ import { CreateScheduleDto } from '../dto/create-schedule.dto';
11
+ import { UpdateScheduleDto } from '../dto/update-schedule.dto';
12
+ import { GetExecutionLogsDto } from '../dto/get-execution-logs.dto';
13
+ import { UserData } from '../../user/entity/user.entity';
14
+ import {
15
+ WORKFLOW_SCHEDULE_QUEUE,
16
+ EXECUTE_SCHEDULED_WORKFLOW_JOB,
17
+ SCHEDULE_STATUS_ACTIVE,
18
+ SCHEDULE_STATUS_PAUSED,
19
+ SCHEDULE_STATUS_INACTIVE,
20
+ DEFAULT_MAX_RETRIES,
21
+ DEFAULT_RETRY_DELAY,
22
+ DEFAULT_BACKOFF_MULTIPLIER,
23
+ DEFAULT_TIMEZONE,
24
+ } from '../constants/schedule.constants';
25
+ import { ScheduleJobData } from '../interfaces/schedule-job-data.interface';
26
+
27
+ /**
28
+ * Workflow Schedule Service
29
+ * Manages scheduled workflows and their execution
30
+ */
31
+ @Injectable()
32
+ export class WorkflowScheduleService {
33
+ private readonly logger = new Logger(WorkflowScheduleService.name);
34
+
35
+ constructor(
36
+ @InjectRepository(ScheduledWorkflow)
37
+ private readonly scheduledWorkflowRepository: Repository<ScheduledWorkflow>,
38
+ @InjectRepository(WorkflowExecutionLog)
39
+ private readonly executionLogRepository: Repository<WorkflowExecutionLog>,
40
+ @InjectQueue(WORKFLOW_SCHEDULE_QUEUE)
41
+ private readonly scheduleQueue: Queue<ScheduleJobData>,
42
+ private readonly dataSource: DataSource,
43
+ ) {}
44
+
45
+ /**
46
+ * 1. Create a new scheduled workflow
47
+ */
48
+ async createSchedule(
49
+ createScheduleDto: CreateScheduleDto,
50
+ loggedInUser: UserData,
51
+ ): Promise<ScheduledWorkflow> {
52
+ this.logger.log(
53
+ `Creating schedule for workflow ${createScheduleDto.workflow_id} by user ${loggedInUser.id}`,
54
+ );
55
+
56
+ try {
57
+ // Validate cron expression
58
+ this.validateCronExpression(createScheduleDto.cron_expression, createScheduleDto.timezone);
59
+
60
+ // Calculate next execution time
61
+ const nextExecutionAt = this.calculateNextExecution(
62
+ createScheduleDto.cron_expression,
63
+ createScheduleDto.timezone || DEFAULT_TIMEZONE,
64
+ );
65
+
66
+ // Create scheduled workflow entity
67
+ const schedule = this.scheduledWorkflowRepository.create({
68
+ workflow_id: createScheduleDto.workflow_id,
69
+ workflow_name: createScheduleDto.workflow_name,
70
+ name: createScheduleDto.name,
71
+ description: createScheduleDto.description,
72
+ cron_expression: createScheduleDto.cron_expression,
73
+ timezone: createScheduleDto.timezone || DEFAULT_TIMEZONE,
74
+ start_date: createScheduleDto.start_date ? new Date(createScheduleDto.start_date) : null,
75
+ end_date: createScheduleDto.end_date ? new Date(createScheduleDto.end_date) : null,
76
+ max_executions: createScheduleDto.max_executions,
77
+ execution_count: 0,
78
+ next_execution_at: nextExecutionAt,
79
+ schedule_status: SCHEDULE_STATUS_ACTIVE,
80
+ retry_config: createScheduleDto.retry_config || {
81
+ maxRetries: DEFAULT_MAX_RETRIES,
82
+ retryDelay: DEFAULT_RETRY_DELAY,
83
+ backoffMultiplier: DEFAULT_BACKOFF_MULTIPLIER,
84
+ },
85
+ metadata: createScheduleDto.metadata || {},
86
+ is_enabled: createScheduleDto.is_enabled !== false,
87
+ organization_id: createScheduleDto.organization_id || loggedInUser.organization_id,
88
+ enterprise_id: createScheduleDto.enterprise_id || loggedInUser.enterprise_id,
89
+ level_id: createScheduleDto.level_id || loggedInUser.level_id,
90
+ level_type: createScheduleDto.level_type || loggedInUser.level_type,
91
+ appcode: createScheduleDto.appcode || loggedInUser.appcode,
92
+ created_by: loggedInUser.id,
93
+ created_date: new Date(),
94
+ status: createScheduleDto.status || 'ACTIVE',
95
+ entity_type: 'WFSC',
96
+ });
97
+
98
+ const savedSchedule = await this.scheduledWorkflowRepository.save(schedule);
99
+
100
+ // Add job to Bull queue with cron schedule
101
+ if (savedSchedule.is_enabled && savedSchedule.schedule_status === SCHEDULE_STATUS_ACTIVE) {
102
+ await this.scheduleJob(savedSchedule, loggedInUser);
103
+ }
104
+
105
+ this.logger.log(`Schedule created successfully with ID: ${savedSchedule.id}`);
106
+ return savedSchedule;
107
+ } catch (error) {
108
+ this.logger.error(`Failed to create schedule: ${error.message}`, error.stack);
109
+ throw error;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * 2. Update an existing scheduled workflow
115
+ */
116
+ async updateSchedule(
117
+ updateScheduleDto: UpdateScheduleDto,
118
+ loggedInUser: UserData,
119
+ ): Promise<ScheduledWorkflow> {
120
+ this.logger.log(`Updating schedule ${updateScheduleDto.id} by user ${loggedInUser.id}`);
121
+
122
+ try {
123
+ const schedule = await this.scheduledWorkflowRepository.findOne({
124
+ where: { id: updateScheduleDto.id },
125
+ });
126
+
127
+ if (!schedule) {
128
+ throw new NotFoundException(`Scheduled workflow not found with ID: ${updateScheduleDto.id}`);
129
+ }
130
+
131
+ // Validate cron expression if updated
132
+ if (updateScheduleDto.cron_expression) {
133
+ this.validateCronExpression(
134
+ updateScheduleDto.cron_expression,
135
+ updateScheduleDto.timezone || schedule.timezone,
136
+ );
137
+ }
138
+
139
+ // Update fields
140
+ if (updateScheduleDto.workflow_id !== undefined) {
141
+ schedule.workflow_id = updateScheduleDto.workflow_id;
142
+ }
143
+ if (updateScheduleDto.workflow_name !== undefined) {
144
+ schedule.workflow_name = updateScheduleDto.workflow_name;
145
+ }
146
+ if (updateScheduleDto.name !== undefined) {
147
+ schedule.name = updateScheduleDto.name;
148
+ }
149
+ if (updateScheduleDto.description !== undefined) {
150
+ schedule.description = updateScheduleDto.description;
151
+ }
152
+ if (updateScheduleDto.cron_expression !== undefined) {
153
+ schedule.cron_expression = updateScheduleDto.cron_expression;
154
+ schedule.next_execution_at = this.calculateNextExecution(
155
+ updateScheduleDto.cron_expression,
156
+ updateScheduleDto.timezone || schedule.timezone,
157
+ );
158
+ }
159
+ if (updateScheduleDto.timezone !== undefined) {
160
+ schedule.timezone = updateScheduleDto.timezone;
161
+ }
162
+ if (updateScheduleDto.start_date !== undefined) {
163
+ schedule.start_date = updateScheduleDto.start_date
164
+ ? new Date(updateScheduleDto.start_date)
165
+ : null;
166
+ }
167
+ if (updateScheduleDto.end_date !== undefined) {
168
+ schedule.end_date = updateScheduleDto.end_date ? new Date(updateScheduleDto.end_date) : null;
169
+ }
170
+ if (updateScheduleDto.max_executions !== undefined) {
171
+ schedule.max_executions = updateScheduleDto.max_executions;
172
+ }
173
+ if (updateScheduleDto.schedule_status !== undefined) {
174
+ schedule.schedule_status = updateScheduleDto.schedule_status;
175
+ }
176
+ if (updateScheduleDto.retry_config !== undefined) {
177
+ schedule.retry_config = updateScheduleDto.retry_config;
178
+ }
179
+ if (updateScheduleDto.actions !== undefined) {
180
+ schedule.actions = updateScheduleDto.actions;
181
+ }
182
+ if (updateScheduleDto.metadata !== undefined) {
183
+ schedule.metadata = updateScheduleDto.metadata;
184
+ }
185
+ if (updateScheduleDto.is_enabled !== undefined) {
186
+ schedule.is_enabled = updateScheduleDto.is_enabled;
187
+ }
188
+ if (updateScheduleDto.status !== undefined) {
189
+ schedule.status = updateScheduleDto.status;
190
+ }
191
+
192
+ schedule.modified_by = loggedInUser.id;
193
+ schedule.modified_date = new Date();
194
+
195
+ const updatedSchedule = await this.scheduledWorkflowRepository.save(schedule);
196
+
197
+ // Remove old job and create new one if schedule changed
198
+ if (schedule.job_id) {
199
+ await this.removeJob(schedule.job_id);
200
+ }
201
+
202
+ if (updatedSchedule.is_enabled && updatedSchedule.schedule_status === SCHEDULE_STATUS_ACTIVE) {
203
+ await this.scheduleJob(updatedSchedule, loggedInUser);
204
+ }
205
+
206
+ this.logger.log(`Schedule updated successfully: ${updatedSchedule.id}`);
207
+ return updatedSchedule;
208
+ } catch (error) {
209
+ this.logger.error(`Failed to update schedule: ${error.message}`, error.stack);
210
+ throw error;
211
+ }
212
+ }
213
+
214
+ /**
215
+ * 3. Get a scheduled workflow by ID
216
+ */
217
+ async getScheduleById(scheduleId: number, loggedInUser: UserData): Promise<ScheduledWorkflow> {
218
+ const schedule = await this.scheduledWorkflowRepository.findOne({
219
+ where: {
220
+ id: scheduleId,
221
+ organization_id: loggedInUser.organization_id,
222
+ },
223
+ });
224
+
225
+ if (!schedule) {
226
+ throw new NotFoundException(`Scheduled workflow not found with ID: ${scheduleId}`);
227
+ }
228
+
229
+ return schedule;
230
+ }
231
+
232
+ /**
233
+ * 4. Get all scheduled workflows with pagination and filters
234
+ */
235
+ async getAllSchedules(
236
+ page: number = 1,
237
+ size: number = 10,
238
+ filters: any = {},
239
+ loggedInUser: UserData,
240
+ ): Promise<{ data: ScheduledWorkflow[]; total: number; page: number; size: number }> {
241
+ const skip = (page - 1) * size;
242
+
243
+ const whereConditions: any = {
244
+ organization_id: loggedInUser.organization_id,
245
+ };
246
+
247
+ if (filters.workflow_id) {
248
+ whereConditions.workflow_id = filters.workflow_id;
249
+ }
250
+ if (filters.schedule_status) {
251
+ whereConditions.schedule_status = filters.schedule_status;
252
+ }
253
+ if (filters.is_enabled !== undefined) {
254
+ whereConditions.is_enabled = filters.is_enabled;
255
+ }
256
+
257
+ const [data, total] = await this.scheduledWorkflowRepository.findAndCount({
258
+ where: whereConditions,
259
+ skip,
260
+ take: size,
261
+ order: { created_date: 'DESC' },
262
+ });
263
+
264
+ return {
265
+ data,
266
+ total,
267
+ page,
268
+ size,
269
+ };
270
+ }
271
+
272
+ /**
273
+ * 5. Pause a scheduled workflow
274
+ */
275
+ async pauseSchedule(scheduleId: number, loggedInUser: UserData): Promise<ScheduledWorkflow> {
276
+ this.logger.log(`Pausing schedule ${scheduleId} by user ${loggedInUser.id}`);
277
+
278
+ const schedule = await this.getScheduleById(scheduleId, loggedInUser);
279
+
280
+ if (schedule.schedule_status === SCHEDULE_STATUS_PAUSED) {
281
+ throw new BadRequestException('Schedule is already paused');
282
+ }
283
+
284
+ schedule.schedule_status = SCHEDULE_STATUS_PAUSED;
285
+ schedule.modified_by = loggedInUser.id;
286
+ schedule.modified_date = new Date();
287
+
288
+ const updatedSchedule = await this.scheduledWorkflowRepository.save(schedule);
289
+
290
+ // Remove job from queue
291
+ if (schedule.job_id) {
292
+ await this.removeJob(schedule.job_id);
293
+ updatedSchedule.job_id = null;
294
+ await this.scheduledWorkflowRepository.save(updatedSchedule);
295
+ }
296
+
297
+ this.logger.log(`Schedule paused successfully: ${scheduleId}`);
298
+ return updatedSchedule;
299
+ }
300
+
301
+ /**
302
+ * 6. Resume a paused scheduled workflow
303
+ */
304
+ async resumeSchedule(scheduleId: number, loggedInUser: UserData): Promise<ScheduledWorkflow> {
305
+ this.logger.log(`Resuming schedule ${scheduleId} by user ${loggedInUser.id}`);
306
+
307
+ const schedule = await this.getScheduleById(scheduleId, loggedInUser);
308
+
309
+ if (schedule.schedule_status !== SCHEDULE_STATUS_PAUSED) {
310
+ throw new BadRequestException('Schedule is not paused');
311
+ }
312
+
313
+ schedule.schedule_status = SCHEDULE_STATUS_ACTIVE;
314
+ schedule.modified_by = loggedInUser.id;
315
+ schedule.modified_date = new Date();
316
+
317
+ // Recalculate next execution time
318
+ schedule.next_execution_at = this.calculateNextExecution(
319
+ schedule.cron_expression,
320
+ schedule.timezone,
321
+ );
322
+
323
+ const updatedSchedule = await this.scheduledWorkflowRepository.save(schedule);
324
+
325
+ // Re-add job to queue
326
+ if (updatedSchedule.is_enabled) {
327
+ await this.scheduleJob(updatedSchedule, loggedInUser);
328
+ }
329
+
330
+ this.logger.log(`Schedule resumed successfully: ${scheduleId}`);
331
+ return updatedSchedule;
332
+ }
333
+
334
+ /**
335
+ * 7. Delete a scheduled workflow
336
+ */
337
+ async deleteSchedule(scheduleId: number, loggedInUser: UserData): Promise<void> {
338
+ this.logger.log(`Deleting schedule ${scheduleId} by user ${loggedInUser.id}`);
339
+
340
+ const schedule = await this.getScheduleById(scheduleId, loggedInUser);
341
+
342
+ // Remove job from queue
343
+ if (schedule.job_id) {
344
+ await this.removeJob(schedule.job_id);
345
+ }
346
+
347
+ // Soft delete by setting status to inactive
348
+ schedule.schedule_status = SCHEDULE_STATUS_INACTIVE;
349
+ schedule.status = 'INACTIVE';
350
+ schedule.is_enabled = false;
351
+ schedule.modified_by = loggedInUser.id;
352
+ schedule.modified_date = new Date();
353
+
354
+ await this.scheduledWorkflowRepository.save(schedule);
355
+
356
+ this.logger.log(`Schedule deleted successfully: ${scheduleId}`);
357
+ }
358
+
359
+ /**
360
+ * 8. Manually trigger a scheduled workflow execution
361
+ */
362
+ async triggerManualExecution(
363
+ scheduleId: number,
364
+ loggedInUser: UserData,
365
+ metadata?: Record<string, any>,
366
+ ): Promise<{ executionLogId: number; jobId: string }> {
367
+ this.logger.log(`Manual trigger for schedule ${scheduleId} by user ${loggedInUser.id}`);
368
+
369
+ const schedule = await this.getScheduleById(scheduleId, loggedInUser);
370
+
371
+ const jobData: ScheduleJobData = {
372
+ scheduleId: schedule.id,
373
+ workflowId: schedule.workflow_id,
374
+ workflowName: schedule.workflow_name,
375
+ organizationId: schedule.organization_id,
376
+ enterpriseId: schedule.enterprise_id,
377
+ levelId: schedule.level_id,
378
+ levelType: schedule.level_type,
379
+ appcode: schedule.appcode,
380
+ createdBy: loggedInUser.id,
381
+ triggeredBy: 'MANUAL',
382
+ triggeredAt: new Date(),
383
+ metadata: metadata || {},
384
+ };
385
+
386
+ // Add job to queue immediately (not scheduled)
387
+ const job = await this.scheduleQueue.add(EXECUTE_SCHEDULED_WORKFLOW_JOB, jobData, {
388
+ attempts: schedule.retry_config?.maxRetries || DEFAULT_MAX_RETRIES,
389
+ backoff: {
390
+ type: 'exponential',
391
+ delay: schedule.retry_config?.retryDelay || DEFAULT_RETRY_DELAY,
392
+ },
393
+ });
394
+
395
+ // Create execution log entry
396
+ const executionLog = this.executionLogRepository.create({
397
+ schedule_id: schedule.id,
398
+ workflow_id: schedule.workflow_id,
399
+ job_id: job.id.toString(),
400
+ execution_status: 'PENDING',
401
+ triggered_by: 'MANUAL',
402
+ triggered_by_user_id: loggedInUser.id,
403
+ organization_id: schedule.organization_id,
404
+ enterprise_id: schedule.enterprise_id,
405
+ created_by: loggedInUser.id,
406
+ created_date: new Date(),
407
+ entity_type: 'WFEL',
408
+ status: 'ACTIVE',
409
+ });
410
+
411
+ const savedLog = await this.executionLogRepository.save(executionLog);
412
+
413
+ this.logger.log(`Manual execution triggered for schedule ${scheduleId}, job ID: ${job.id}`);
414
+
415
+ return {
416
+ executionLogId: savedLog.id,
417
+ jobId: job.id.toString(),
418
+ };
419
+ }
420
+
421
+ /**
422
+ * 9. Get execution logs with filters and pagination
423
+ */
424
+ async getExecutionLogs(
425
+ getExecutionLogsDto: GetExecutionLogsDto,
426
+ loggedInUser: UserData,
427
+ ): Promise<{ data: WorkflowExecutionLog[]; total: number; page: number; size: number }> {
428
+ const page = getExecutionLogsDto.page || 1;
429
+ const size = getExecutionLogsDto.size || 10;
430
+ const skip = (page - 1) * size;
431
+
432
+ const whereConditions: any = {
433
+ organization_id: getExecutionLogsDto.organization_id || loggedInUser.organization_id,
434
+ };
435
+
436
+ if (getExecutionLogsDto.schedule_id) {
437
+ whereConditions.schedule_id = getExecutionLogsDto.schedule_id;
438
+ }
439
+ if (getExecutionLogsDto.workflow_id) {
440
+ whereConditions.workflow_id = getExecutionLogsDto.workflow_id;
441
+ }
442
+ if (getExecutionLogsDto.execution_status) {
443
+ whereConditions.execution_status = getExecutionLogsDto.execution_status;
444
+ }
445
+ if (getExecutionLogsDto.execution_statuses && getExecutionLogsDto.execution_statuses.length > 0) {
446
+ whereConditions.execution_status = In(getExecutionLogsDto.execution_statuses);
447
+ }
448
+ if (getExecutionLogsDto.triggered_by) {
449
+ whereConditions.triggered_by = getExecutionLogsDto.triggered_by;
450
+ }
451
+ if (getExecutionLogsDto.triggered_by_user_id) {
452
+ whereConditions.triggered_by_user_id = getExecutionLogsDto.triggered_by_user_id;
453
+ }
454
+
455
+ // Date range filter
456
+ if (getExecutionLogsDto.start_date && getExecutionLogsDto.end_date) {
457
+ whereConditions.created_date = Between(
458
+ new Date(getExecutionLogsDto.start_date),
459
+ new Date(getExecutionLogsDto.end_date),
460
+ );
461
+ }
462
+
463
+ const [data, total] = await this.executionLogRepository.findAndCount({
464
+ where: whereConditions,
465
+ skip,
466
+ take: size,
467
+ order: {
468
+ [getExecutionLogsDto.sortBy || 'created_date']:
469
+ getExecutionLogsDto.sortOrder || 'DESC',
470
+ },
471
+ });
472
+
473
+ return {
474
+ data,
475
+ total,
476
+ page,
477
+ size,
478
+ };
479
+ }
480
+
481
+ /**
482
+ * Get execution statistics for a schedule
483
+ */
484
+ async getExecutionStats(scheduleId: number, loggedInUser: UserData): Promise<any> {
485
+ const schedule = await this.getScheduleById(scheduleId, loggedInUser);
486
+
487
+ const stats = await this.dataSource.query(
488
+ `SELECT
489
+ COUNT(*) as total_executions,
490
+ SUM(CASE WHEN execution_status = 'COMPLETED' THEN 1 ELSE 0 END) as successful_executions,
491
+ SUM(CASE WHEN execution_status = 'FAILED' THEN 1 ELSE 0 END) as failed_executions,
492
+ SUM(CASE WHEN execution_status = 'PENDING' THEN 1 ELSE 0 END) as pending_executions,
493
+ SUM(CASE WHEN execution_status = 'RUNNING' THEN 1 ELSE 0 END) as running_executions,
494
+ AVG(duration_ms) as average_duration_ms,
495
+ SUM(total_records) as total_records_processed
496
+ FROM cr_wf_execution_log
497
+ WHERE schedule_id = ?`,
498
+ [scheduleId],
499
+ );
500
+
501
+ const result = stats[0];
502
+ const successRate =
503
+ result.total_executions > 0
504
+ ? (result.successful_executions / result.total_executions) * 100
505
+ : 0;
506
+
507
+ return {
508
+ schedule_id: scheduleId,
509
+ schedule_name: schedule.name,
510
+ total_executions: parseInt(result.total_executions),
511
+ successful_executions: parseInt(result.successful_executions),
512
+ failed_executions: parseInt(result.failed_executions),
513
+ pending_executions: parseInt(result.pending_executions),
514
+ running_executions: parseInt(result.running_executions),
515
+ average_duration_ms: parseFloat(result.average_duration_ms) || 0,
516
+ total_records_processed: parseInt(result.total_records_processed) || 0,
517
+ success_rate_percentage: parseFloat(successRate.toFixed(2)),
518
+ };
519
+ }
520
+
521
+ /**
522
+ * Private helper: Schedule a job in Bull queue
523
+ */
524
+ private async scheduleJob(schedule: ScheduledWorkflow, loggedInUser: UserData): Promise<void> {
525
+ const jobData: ScheduleJobData = {
526
+ scheduleId: schedule.id,
527
+ workflowId: schedule.workflow_id,
528
+ workflowName: schedule.workflow_name,
529
+ organizationId: schedule.organization_id,
530
+ enterpriseId: schedule.enterprise_id,
531
+ levelId: schedule.level_id,
532
+ levelType: schedule.level_type,
533
+ appcode: schedule.appcode,
534
+ createdBy: loggedInUser.id,
535
+ triggeredBy: 'SCHEDULE',
536
+ triggeredAt: new Date(),
537
+ metadata: schedule.metadata || {},
538
+ };
539
+
540
+ const job = await this.scheduleQueue.add(EXECUTE_SCHEDULED_WORKFLOW_JOB, jobData, {
541
+ repeat: {
542
+ cron: schedule.cron_expression,
543
+ tz: schedule.timezone,
544
+ startDate: schedule.start_date || undefined,
545
+ endDate: schedule.end_date || undefined,
546
+ },
547
+ attempts: schedule.retry_config?.maxRetries || DEFAULT_MAX_RETRIES,
548
+ backoff: {
549
+ type: 'exponential',
550
+ delay: schedule.retry_config?.retryDelay || DEFAULT_RETRY_DELAY,
551
+ },
552
+ });
553
+
554
+ schedule.job_id = job.id.toString();
555
+ await this.scheduledWorkflowRepository.save(schedule);
556
+
557
+ this.logger.log(`Job scheduled with ID: ${job.id} for schedule ${schedule.id}`);
558
+ }
559
+
560
+ /**
561
+ * Private helper: Remove a job from Bull queue
562
+ */
563
+ private async removeJob(jobId: string): Promise<void> {
564
+ try {
565
+ const job = await this.scheduleQueue.getJob(jobId);
566
+ if (job) {
567
+ await job.remove();
568
+ this.logger.log(`Job removed: ${jobId}`);
569
+ }
570
+ } catch (error) {
571
+ this.logger.warn(`Failed to remove job ${jobId}: ${error.message}`);
572
+ }
573
+ }
574
+
575
+ /**
576
+ * Private helper: Validate cron expression
577
+ */
578
+ private validateCronExpression(cronExpression: string, timezone: string): void {
579
+ try {
580
+ cronParser.CronExpressionParser.parse(cronExpression, { tz: timezone });
581
+ } catch (error: any) {
582
+ throw new BadRequestException(
583
+ `Invalid cron expression: ${cronExpression}. Error: ${error.message}`,
584
+ );
585
+ }
586
+ }
587
+
588
+ /**
589
+ * Private helper: Calculate next execution time
590
+ */
591
+ private calculateNextExecution(cronExpression: string, timezone: string): Date | null {
592
+ try {
593
+ const interval = cronParser.CronExpressionParser.parse(cronExpression, { tz: timezone });
594
+ return interval.next().toDate();
595
+ } catch (error: any) {
596
+ this.logger.error(`Failed to calculate next execution: ${error.message}`);
597
+ return null;
598
+ }
599
+ }
600
+ }