rez_core 5.0.16 → 5.0.18

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 (428) hide show
  1. package/.prettierrc +3 -3
  2. package/README.md +99 -99
  3. package/dist/module/auth/guards/role.guard.js +3 -3
  4. package/dist/module/auth/services/auth.service.js +2 -2
  5. package/dist/module/entity_json/service/entity_json.service.js +2 -2
  6. package/dist/module/filter/repository/saved-filter.repository.js +4 -4
  7. package/dist/module/filter/service/filter-evaluator.service.js +2 -2
  8. package/dist/module/filter/service/filter.service.js +22 -22
  9. package/dist/module/integration/examples/usage.example.js +9 -9
  10. package/dist/module/integration/service/integration.service.js +1 -1
  11. package/dist/module/integration/service/wrapper.service.js +26 -26
  12. package/dist/module/listmaster/service/list-master-item.service.js +2 -2
  13. package/dist/module/mapper/service/field-mapper.service.js +4 -4
  14. package/dist/module/mapper/service/mapper.service.js +2 -2
  15. package/dist/module/meta/repository/entity-attribute-update.repository.js +3 -3
  16. package/dist/module/meta/repository/entity-master.repository.js +6 -6
  17. package/dist/module/meta/service/entity-dynamic.service.js +45 -45
  18. package/dist/module/meta/service/entity-dynamic.service.js.map +1 -1
  19. package/dist/module/meta/service/entity-list.service.js +3 -3
  20. package/dist/module/meta/service/entity-master.service.js +3 -3
  21. package/dist/module/meta/service/entity-relation.service.js +9 -9
  22. package/dist/module/meta/service/entity-service-impl.service.js +3 -3
  23. package/dist/module/meta/service/resolver.service.js +3 -3
  24. package/dist/module/module/repository/menu.repository.js +12 -12
  25. package/dist/module/notification/service/notification.service.js +10 -10
  26. package/dist/module/user/controller/login.controller.js +18 -18
  27. package/dist/module/user/service/role.service.js +4 -4
  28. package/dist/module/user/service/user-session.service.js +2 -2
  29. package/dist/module/workflow/repository/action.repository.js +20 -20
  30. package/dist/module/workflow/repository/comm-template.repository.js +6 -6
  31. package/dist/module/workflow/repository/form-master.repository.js +2 -2
  32. package/dist/module/workflow/repository/stage-group.repository.js +26 -26
  33. package/dist/module/workflow/repository/stage-movement.repository.js +15 -15
  34. package/dist/module/workflow/repository/stage.repository.js +8 -8
  35. package/dist/module/workflow/service/action-template-mapping.service.js +31 -31
  36. package/dist/module/workflow/service/action.service.js +7 -7
  37. package/dist/module/workflow/service/entity-modification.service.js +6 -6
  38. package/dist/module/workflow/service/stage-group.service.d.ts +6 -2
  39. package/dist/module/workflow/service/stage-group.service.js +39 -13
  40. package/dist/module/workflow/service/stage-group.service.js.map +1 -1
  41. package/dist/module/workflow/service/stage.service.js +2 -2
  42. package/dist/module/workflow/service/task.service.js +35 -35
  43. package/dist/module/workflow/service/workflow-list-master.service.js +15 -15
  44. package/dist/module/workflow/service/workflow-meta.service.js +26 -26
  45. package/dist/module/workflow/service/workflow.service.js +2 -2
  46. package/dist/module/workflow/workflow.module.js +3 -1
  47. package/dist/module/workflow/workflow.module.js.map +1 -1
  48. package/dist/module/workflow-automation/service/schedule-handler.service.js +14 -14
  49. package/dist/module/workflow-schedule/processors/schedule.processor.js +4 -4
  50. package/dist/module/workflow-schedule/service/workflow-schedule.service.js +9 -9
  51. package/dist/tsconfig.build.tsbuildinfo +1 -1
  52. package/dist/utils/service/reflection-helper.service.js +2 -2
  53. package/docs/modules/event-driven-integration-design.md +91 -91
  54. package/docs/modules/integration.md +250 -250
  55. package/eslint.config.mjs +34 -34
  56. package/nest-cli.json +14 -14
  57. package/package.json +124 -124
  58. package/src/app.controller.ts +12 -12
  59. package/src/app.module.ts +66 -66
  60. package/src/app.service.ts +8 -8
  61. package/src/config/bull.config.ts +69 -69
  62. package/src/config/config.module.ts +17 -17
  63. package/src/config/database.config.ts +48 -48
  64. package/src/constant/global.constant.ts +67 -67
  65. package/src/core.module.ts +88 -88
  66. package/src/decorators/roles.decorator.ts +7 -7
  67. package/src/dtos/response.dto.ts +6 -6
  68. package/src/dtos/response.ts +5 -5
  69. package/src/index.ts +1 -1
  70. package/src/module/auth/auth.module.ts +49 -49
  71. package/src/module/auth/controller/auth.controller.ts +28 -28
  72. package/src/module/auth/guards/google-auth.guard.ts +9 -9
  73. package/src/module/auth/guards/jwt.guard.ts +22 -22
  74. package/src/module/auth/guards/role.guard.ts +68 -68
  75. package/src/module/auth/services/auth.service.ts +50 -50
  76. package/src/module/auth/services/jwt.service.ts +11 -11
  77. package/src/module/auth/strategies/google.strategy.ts +54 -54
  78. package/src/module/auth/strategies/jwt.strategy.ts +58 -58
  79. package/src/module/auth/strategies/local.strategy.ts +13 -13
  80. package/src/module/dashboard/controller/dashboard.controller.ts +36 -36
  81. package/src/module/dashboard/dashboard.module.ts +21 -21
  82. package/src/module/dashboard/entity/dashboard_page_data.entity.ts +27 -27
  83. package/src/module/dashboard/entity/widget_master.entity.ts +18 -18
  84. package/src/module/dashboard/repository/dashboard.repository.ts +42 -42
  85. package/src/module/dashboard/service/dashboard.service.ts +73 -73
  86. package/src/module/dev/dev.module.ts +12 -12
  87. package/src/module/dev/service/dev.service.ts +7 -7
  88. package/src/module/enterprise/controller/organization.controller.ts +36 -36
  89. package/src/module/enterprise/enterprise.module.ts +30 -30
  90. package/src/module/enterprise/entity/enterprise.entity.ts +37 -37
  91. package/src/module/enterprise/entity/organization-app-mapping.entity.ts +13 -13
  92. package/src/module/enterprise/entity/organization.entity.ts +92 -92
  93. package/src/module/enterprise/repository/enterprise.repository.ts +31 -31
  94. package/src/module/enterprise/repository/organization.repository.ts +26 -26
  95. package/src/module/enterprise/repository/school.repository.ts +278 -278
  96. package/src/module/enterprise/service/brand.service.ts +5 -5
  97. package/src/module/enterprise/service/enterprise.service.ts +16 -16
  98. package/src/module/enterprise/service/organization-app-mapping.service.ts +4 -4
  99. package/src/module/enterprise/service/organization.service.ts +145 -145
  100. package/src/module/entity_json/controller/entity_json.controller.ts +47 -47
  101. package/src/module/entity_json/entity_json.module.ts +15 -15
  102. package/src/module/entity_json/service/entity_json.service.ts +265 -265
  103. package/src/module/filter/controller/filter.controller.ts +84 -84
  104. package/src/module/filter/dto/filter-request.dto.ts +38 -38
  105. package/src/module/filter/entity/saved-filter-detail.entity.ts +41 -41
  106. package/src/module/filter/entity/saved-filter-master.entity.ts +23 -23
  107. package/src/module/filter/filter.module.ts +31 -31
  108. package/src/module/filter/repository/saved-filter.repository.ts +168 -168
  109. package/src/module/filter/service/filter-evaluator.service.ts +86 -86
  110. package/src/module/filter/service/filter.service.ts +1051 -1051
  111. package/src/module/filter/service/saved-filter.service.ts +170 -170
  112. package/src/module/ics/controller/ics.controller.ts +21 -21
  113. package/src/module/ics/dto/ics.dto.ts +55 -55
  114. package/src/module/ics/ics.module.ts +13 -13
  115. package/src/module/ics/service/ics.service.ts +57 -57
  116. package/src/module/integration/controller/calender-event.controller.ts +31 -31
  117. package/src/module/integration/controller/integration.controller.ts +662 -662
  118. package/src/module/integration/controller/wrapper.controller.ts +37 -37
  119. package/src/module/integration/dto/create-config.dto.ts +526 -526
  120. package/src/module/integration/entity/integration-config.entity.ts +112 -112
  121. package/src/module/integration/entity/integration-entity-mapper.entity.ts +14 -14
  122. package/src/module/integration/entity/integration-source.entity.ts +17 -17
  123. package/src/module/integration/entity/user-integration.entity.ts +71 -71
  124. package/src/module/integration/examples/usage.example.ts +338 -338
  125. package/src/module/integration/factories/base.factory.ts +7 -7
  126. package/src/module/integration/factories/email.factory.ts +49 -49
  127. package/src/module/integration/factories/integration.factory.ts +121 -121
  128. package/src/module/integration/factories/sms.factory.ts +51 -51
  129. package/src/module/integration/factories/telephone.factory.ts +41 -41
  130. package/src/module/integration/factories/whatsapp.factory.ts +56 -56
  131. package/src/module/integration/integration.module.ts +110 -110
  132. package/src/module/integration/service/calendar-event.service.ts +118 -118
  133. package/src/module/integration/service/integration-entity-mapper.service.ts +17 -17
  134. package/src/module/integration/service/integration-queue.service.ts +229 -229
  135. package/src/module/integration/service/integration.service.ts +2633 -2633
  136. package/src/module/integration/service/oauth.service.ts +224 -224
  137. package/src/module/integration/service/wrapper.service.ts +701 -701
  138. package/src/module/integration/strategies/email/gmail-api.strategy.ts +280 -280
  139. package/src/module/integration/strategies/email/outlook-api.strategy.ts +44 -44
  140. package/src/module/integration/strategies/email/outlook.strategy.ts +64 -64
  141. package/src/module/integration/strategies/email/sendgrid-api.strategy.ts +260 -260
  142. package/src/module/integration/strategies/integration.strategy.ts +97 -97
  143. package/src/module/integration/strategies/sms/gupshup-sms.strategy.ts +146 -146
  144. package/src/module/integration/strategies/sms/msg91-sms.strategy.ts +164 -164
  145. package/src/module/integration/strategies/sms/tubelight-sms.strategy.ts +163 -163
  146. package/src/module/integration/strategies/telephone/ozonetel-voice.strategy.ts +238 -238
  147. package/src/module/integration/strategies/telephone/tubelight-voice.strategy.ts +210 -210
  148. package/src/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.ts +359 -359
  149. package/src/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.ts +372 -372
  150. package/src/module/integration/strategies/whatsapp/whatsapp-cloud.strategy.ts +403 -403
  151. package/src/module/integration/strategies/whatsapp/whatsapp.strategy.ts +57 -57
  152. package/src/module/layout/controller/layout.controller.ts +47 -47
  153. package/src/module/layout/entity/header-items.entity.ts +28 -28
  154. package/src/module/layout/entity/header-section.entity.ts +19 -19
  155. package/src/module/layout/layout.module.ts +21 -21
  156. package/src/module/layout/repository/header-items.repository.ts +18 -18
  157. package/src/module/layout/repository/header-section.repository.ts +22 -22
  158. package/src/module/layout/service/header-section.service.ts +25 -25
  159. package/src/module/layout_preference/controller/layout_preference.controller.ts +73 -73
  160. package/src/module/layout_preference/entity/layout_preference.entity.ts +28 -28
  161. package/src/module/layout_preference/layout_preference.module.ts +22 -22
  162. package/src/module/layout_preference/repository/layout_preference.repository.ts +65 -65
  163. package/src/module/layout_preference/service/layout_preference.service.ts +191 -191
  164. package/src/module/lead/controller/lead.controller.ts +30 -30
  165. package/src/module/lead/lead.module.ts +14 -14
  166. package/src/module/lead/repository/lead.repository.ts +41 -41
  167. package/src/module/lead/service/lead.service.ts +54 -54
  168. package/src/module/linked_attributes/controller/linked_attributes.controller.ts +10 -10
  169. package/src/module/linked_attributes/entity/linked_attribute.entity.ts +48 -48
  170. package/src/module/linked_attributes/linked_attributes.module.ts +16 -16
  171. package/src/module/linked_attributes/repository/linked_attribute.repository.ts +12 -12
  172. package/src/module/linked_attributes/service/linked_attributes.service.ts +22 -22
  173. package/src/module/listmaster/controller/list-master.controller.ts +230 -230
  174. package/src/module/listmaster/entity/list-master-items.entity.ts +43 -43
  175. package/src/module/listmaster/entity/list-master.entity.ts +33 -33
  176. package/src/module/listmaster/listmaster.module.ts +46 -46
  177. package/src/module/listmaster/repository/list-master-items.repository.ts +169 -169
  178. package/src/module/listmaster/repository/list-master.repository.ts +46 -46
  179. package/src/module/listmaster/service/list-master-engine.ts +19 -19
  180. package/src/module/listmaster/service/list-master-extension.interface.ts +4 -4
  181. package/src/module/listmaster/service/list-master-item.service.ts +292 -292
  182. package/src/module/listmaster/service/list-master-registry.ts +15 -15
  183. package/src/module/listmaster/service/list-master.service.ts +535 -535
  184. package/src/module/mapper/controller/field-mapper.controller.ts +76 -76
  185. package/src/module/mapper/controller/mapper.controller.ts +20 -20
  186. package/src/module/mapper/dto/field-mapper.dto.ts +14 -14
  187. package/src/module/mapper/entity/field-lovs.entity.ts +19 -19
  188. package/src/module/mapper/entity/field-mapper.entity.ts +53 -53
  189. package/src/module/mapper/entity/mapper.entity.ts +16 -16
  190. package/src/module/mapper/mapper.module.ts +34 -34
  191. package/src/module/mapper/repository/field-lovs.repository.ts +35 -35
  192. package/src/module/mapper/repository/field-mapper.repository.ts +42 -42
  193. package/src/module/mapper/repository/mapper.repository.ts +15 -15
  194. package/src/module/mapper/service/field-mapper.service.ts +271 -271
  195. package/src/module/mapper/service/mapper.service.ts +79 -79
  196. package/src/module/master/controller/master.controller.ts +74 -74
  197. package/src/module/master/service/master.service.ts +483 -483
  198. package/src/module/meta/controller/app-master.controller.ts +38 -38
  199. package/src/module/meta/controller/attribute-master.controller.ts +86 -86
  200. package/src/module/meta/controller/entity-dynamic.controller.ts +125 -125
  201. package/src/module/meta/controller/entity-master.controller.ts +41 -41
  202. package/src/module/meta/controller/entity-relation.controller.ts +36 -36
  203. package/src/module/meta/controller/entity.controller.ts +392 -392
  204. package/src/module/meta/controller/entity.public.controller.ts +75 -75
  205. package/src/module/meta/controller/media.controller.ts +107 -107
  206. package/src/module/meta/controller/meta.controller.ts +96 -96
  207. package/src/module/meta/controller/view-master.controller.ts +86 -86
  208. package/src/module/meta/dto/entity-list-data.dto.ts +6 -6
  209. package/src/module/meta/dto/entity-tab.dto.ts +4 -4
  210. package/src/module/meta/dto/entity-table.dto.ts +9 -9
  211. package/src/module/meta/entity/app-master.entity.ts +34 -34
  212. package/src/module/meta/entity/attribute-master.entity.ts +89 -89
  213. package/src/module/meta/entity/base-entity.entity.ts +75 -75
  214. package/src/module/meta/entity/entity-master.entity.ts +85 -85
  215. package/src/module/meta/entity/entity-relation-data.entity.ts +29 -29
  216. package/src/module/meta/entity/entity-relation.entity.ts +23 -23
  217. package/src/module/meta/entity/entity-table-column.entity.ts +61 -61
  218. package/src/module/meta/entity/entity-table.entity.ts +50 -50
  219. package/src/module/meta/entity/media-data.entity.ts +32 -32
  220. package/src/module/meta/entity/preference.entity.ts +62 -62
  221. package/src/module/meta/entity/view-master.entity.ts +41 -41
  222. package/src/module/meta/entity.module.ts +166 -166
  223. package/src/module/meta/repository/app-master.repository.ts +20 -20
  224. package/src/module/meta/repository/attribute-master.repository.ts +138 -138
  225. package/src/module/meta/repository/entity-attribute-update.repository.ts +44 -44
  226. package/src/module/meta/repository/entity-master.repository.ts +111 -111
  227. package/src/module/meta/repository/entity-table-column.repository.ts +39 -39
  228. package/src/module/meta/repository/entity-table.repository.ts +53 -53
  229. package/src/module/meta/repository/media-data.repository.ts +50 -50
  230. package/src/module/meta/repository/preference.repository.ts +20 -20
  231. package/src/module/meta/repository/user-app-mapping.repository.ts +28 -28
  232. package/src/module/meta/repository/view-master.repository.ts +42 -42
  233. package/src/module/meta/service/app-master.service.ts +37 -37
  234. package/src/module/meta/service/attribute-master.service.ts +130 -130
  235. package/src/module/meta/service/common.service.ts +9 -9
  236. package/src/module/meta/service/entity-attribute-update.service.ts +28 -28
  237. package/src/module/meta/service/entity-dynamic.service.ts +818 -818
  238. package/src/module/meta/service/entity-list.service.ts +205 -205
  239. package/src/module/meta/service/entity-master.service.ts +175 -175
  240. package/src/module/meta/service/entity-realation-data.service.ts +9 -9
  241. package/src/module/meta/service/entity-relation.service.ts +87 -87
  242. package/src/module/meta/service/entity-service-impl.service.ts +525 -525
  243. package/src/module/meta/service/entity-table-column.service.ts +39 -39
  244. package/src/module/meta/service/entity-table.service.ts +150 -150
  245. package/src/module/meta/service/entity-validation.service.ts +187 -187
  246. package/src/module/meta/service/entity.service.ts +67 -67
  247. package/src/module/meta/service/field-group.service.ts +103 -103
  248. package/src/module/meta/service/media-data.service.ts +507 -507
  249. package/src/module/meta/service/populate-meta.service.ts +193 -193
  250. package/src/module/meta/service/preference.service.ts +16 -16
  251. package/src/module/meta/service/resolver.service.ts +271 -271
  252. package/src/module/meta/service/section-master.service.ts +104 -104
  253. package/src/module/meta/service/update-form-json.service.ts +22 -22
  254. package/src/module/meta/service/user-app-mapping.service.ts +17 -17
  255. package/src/module/meta/service/view-master.service.ts +127 -127
  256. package/src/module/microservice-client/microservice-clients.module.ts +13 -13
  257. package/src/module/microservice-client/service/microservice-client-factory.ts +37 -37
  258. package/src/module/microservice-client/service/microservice-clients.ts +4 -4
  259. package/src/module/module/controller/menu.controller.ts +15 -15
  260. package/src/module/module/controller/module-access.controller.ts +134 -134
  261. package/src/module/module/entity/menu.entity.ts +43 -43
  262. package/src/module/module/entity/module-access.entity.ts +25 -25
  263. package/src/module/module/entity/module-action.entity.ts +17 -17
  264. package/src/module/module/entity/module.entity.ts +52 -52
  265. package/src/module/module/module.module.ts +42 -42
  266. package/src/module/module/repository/menu.repository.ts +184 -184
  267. package/src/module/module/repository/module-access.repository.ts +344 -344
  268. package/src/module/module/service/menu.service.ts +82 -82
  269. package/src/module/module/service/module-access.service.ts +194 -194
  270. package/src/module/notification/controller/notification.controller.ts +58 -58
  271. package/src/module/notification/controller/otp.controller.ts +117 -117
  272. package/src/module/notification/entity/notification.entity.ts +26 -26
  273. package/src/module/notification/entity/otp.entity.ts +28 -28
  274. package/src/module/notification/firebase-admin.config.ts +22 -22
  275. package/src/module/notification/notification.module.ts +69 -69
  276. package/src/module/notification/repository/otp.repository.ts +27 -27
  277. package/src/module/notification/service/email.service.ts +127 -127
  278. package/src/module/notification/service/notification.service.ts +160 -160
  279. package/src/module/notification/service/otp.service.ts +132 -132
  280. package/src/module/third-party-module/entity/third-party-api-registry.entity.ts +52 -52
  281. package/src/module/third-party-module/repository/third-party-api-registry.repository.ts +20 -20
  282. package/src/module/third-party-module/service/api-registry.service.ts +13 -13
  283. package/src/module/third-party-module/third-party.module.ts +12 -12
  284. package/src/module/user/controller/login.controller.ts +197 -197
  285. package/src/module/user/controller/user.controller.ts +40 -40
  286. package/src/module/user/dto/create-user.dto.ts +62 -62
  287. package/src/module/user/dto/update-user.dto.ts +4 -4
  288. package/src/module/user/entity/role.entity.ts +33 -33
  289. package/src/module/user/entity/user-role-mapping.entity.ts +38 -38
  290. package/src/module/user/entity/user-session.entity.ts +73 -73
  291. package/src/module/user/entity/user.entity.ts +59 -59
  292. package/src/module/user/repository/role.repository.ts +96 -96
  293. package/src/module/user/repository/user-role-mapping.repository.ts +126 -126
  294. package/src/module/user/repository/user.repository.ts +50 -50
  295. package/src/module/user/repository/userSession.repository.ts +33 -33
  296. package/src/module/user/service/login.service.ts +304 -304
  297. package/src/module/user/service/role.service.ts +189 -189
  298. package/src/module/user/service/user-role-mapping.service.ts +98 -98
  299. package/src/module/user/service/user-session.service.ts +168 -168
  300. package/src/module/user/service/user.service.ts +365 -365
  301. package/src/module/user/user.module.ts +65 -65
  302. package/src/module/workflow/controller/action-category.controller.ts +54 -54
  303. package/src/module/workflow/controller/action-resource-mapping.controller.ts +23 -23
  304. package/src/module/workflow/controller/action-template-mapping.controller.ts +35 -35
  305. package/src/module/workflow/controller/action.controller.ts +111 -111
  306. package/src/module/workflow/controller/activity-log.controller.ts +55 -55
  307. package/src/module/workflow/controller/comm-template.controller.ts +43 -43
  308. package/src/module/workflow/controller/entity-modification.controller.ts +35 -35
  309. package/src/module/workflow/controller/form-master.controller.ts +43 -43
  310. package/src/module/workflow/controller/stage-group.controller.ts +48 -48
  311. package/src/module/workflow/controller/stage.controller.ts +50 -50
  312. package/src/module/workflow/controller/task.controller.ts +77 -77
  313. package/src/module/workflow/controller/workflow-list-master.controller.ts +44 -44
  314. package/src/module/workflow/controller/workflow-meta.controller.ts +80 -80
  315. package/src/module/workflow/controller/workflow.controller.ts +67 -67
  316. package/src/module/workflow/entity/action-category.entity.ts +38 -38
  317. package/src/module/workflow/entity/action-data.entity.ts +55 -55
  318. package/src/module/workflow/entity/action-resources-mapping.entity.ts +29 -29
  319. package/src/module/workflow/entity/action-template-mapping.entity.ts +17 -17
  320. package/src/module/workflow/entity/action.entity.ts +53 -53
  321. package/src/module/workflow/entity/activity-log.entity.ts +43 -43
  322. package/src/module/workflow/entity/comm-template.entity.ts +43 -43
  323. package/src/module/workflow/entity/entity-modification.entity.ts +38 -38
  324. package/src/module/workflow/entity/form.entity.ts +25 -25
  325. package/src/module/workflow/entity/stage-action-mapping.entity.ts +17 -17
  326. package/src/module/workflow/entity/stage-group.entity.ts +23 -23
  327. package/src/module/workflow/entity/stage-movement-data.entity.ts +38 -38
  328. package/src/module/workflow/entity/stage.entity.ts +20 -20
  329. package/src/module/workflow/entity/task-data.entity.ts +88 -88
  330. package/src/module/workflow/entity/template-attach-mapper.entity.ts +30 -30
  331. package/src/module/workflow/entity/workflow-data.entity.ts +11 -11
  332. package/src/module/workflow/entity/workflow-level-mapping.entity.ts +18 -18
  333. package/src/module/workflow/entity/workflow.entity.ts +20 -20
  334. package/src/module/workflow/repository/action-category.repository.ts +79 -79
  335. package/src/module/workflow/repository/action-data.repository.ts +334 -334
  336. package/src/module/workflow/repository/action.repository.ts +323 -323
  337. package/src/module/workflow/repository/activity-log.repository.ts +148 -148
  338. package/src/module/workflow/repository/comm-template.repository.ts +149 -149
  339. package/src/module/workflow/repository/form-master.repository.ts +59 -59
  340. package/src/module/workflow/repository/stage-group.repository.ts +197 -197
  341. package/src/module/workflow/repository/stage-movement.repository.ts +244 -244
  342. package/src/module/workflow/repository/stage.repository.ts +172 -172
  343. package/src/module/workflow/repository/task.repository.ts +134 -134
  344. package/src/module/workflow/repository/workflow.repository.ts +42 -42
  345. package/src/module/workflow/service/action-category.service.ts +33 -33
  346. package/src/module/workflow/service/action-data.service.ts +62 -62
  347. package/src/module/workflow/service/action-resources-mapping.service.ts +10 -10
  348. package/src/module/workflow/service/action-template-mapping.service.ts +115 -115
  349. package/src/module/workflow/service/action.service.ts +279 -279
  350. package/src/module/workflow/service/activity-log.service.ts +107 -107
  351. package/src/module/workflow/service/comm-template.service.ts +180 -180
  352. package/src/module/workflow/service/entity-modification.service.ts +67 -67
  353. package/src/module/workflow/service/form-master.service.ts +35 -35
  354. package/src/module/workflow/service/populate-workflow.service.ts +303 -303
  355. package/src/module/workflow/service/stage-action-mapping.service.ts +5 -5
  356. package/src/module/workflow/service/stage-group.service.ts +345 -319
  357. package/src/module/workflow/service/stage.service.ts +199 -199
  358. package/src/module/workflow/service/task.service.ts +555 -555
  359. package/src/module/workflow/service/workflow-list-master.service.ts +60 -60
  360. package/src/module/workflow/service/workflow-meta.service.ts +654 -654
  361. package/src/module/workflow/service/workflow.service.ts +205 -205
  362. package/src/module/workflow/workflow.module.ts +178 -176
  363. package/src/module/workflow-automation/SCHEDULING_GUIDE.md +145 -145
  364. package/src/module/workflow-automation/controller/workflow-automation.controller.ts +43 -43
  365. package/src/module/workflow-automation/entity/workflow-automation-action.entity.ts +26 -26
  366. package/src/module/workflow-automation/entity/workflow-automation.entity.ts +40 -40
  367. package/src/module/workflow-automation/interface/action.decorator.ts +7 -7
  368. package/src/module/workflow-automation/interface/action.interface.ts +5 -5
  369. package/src/module/workflow-automation/service/action-registery.service.ts +35 -35
  370. package/src/module/workflow-automation/service/schedule-handler.service.ts +149 -149
  371. package/src/module/workflow-automation/service/workflow-automation-engine.service.ts +214 -214
  372. package/src/module/workflow-automation/service/workflow-automation.service.ts +508 -508
  373. package/src/module/workflow-automation/workflow-automation.module.ts +47 -47
  374. package/src/module/workflow-schedule/INSTALLATION.md +244 -244
  375. package/src/module/workflow-schedule/MULTI_PROJECT_GUIDE.md +196 -196
  376. package/src/module/workflow-schedule/README.md +422 -422
  377. package/src/module/workflow-schedule/constants/schedule.constants.ts +48 -48
  378. package/src/module/workflow-schedule/controller/workflow-schedule.controller.ts +255 -255
  379. package/src/module/workflow-schedule/docs/CLAUDE_CODE_GUIDE.md +510 -510
  380. package/src/module/workflow-schedule/docs/CLAUDE_CODE_PROMPT.md +362 -362
  381. package/src/module/workflow-schedule/docs/RUN_CLAUDE_CODE.sh +68 -68
  382. package/src/module/workflow-schedule/dto/create-schedule.dto.ts +147 -147
  383. package/src/module/workflow-schedule/dto/get-execution-logs.dto.ts +119 -119
  384. package/src/module/workflow-schedule/dto/update-schedule.dto.ts +96 -96
  385. package/src/module/workflow-schedule/entities/scheduled-workflow.entity.ts +148 -148
  386. package/src/module/workflow-schedule/entities/workflow-execution-log.entity.ts +154 -154
  387. package/src/module/workflow-schedule/interfaces/schedule-job-data.interface.ts +53 -53
  388. package/src/module/workflow-schedule/interfaces/workflow-schedule-options.interface.ts +12 -12
  389. package/src/module/workflow-schedule/processors/schedule.processor.ts +584 -584
  390. package/src/module/workflow-schedule/service/workflow-schedule.service.ts +600 -600
  391. package/src/module/workflow-schedule/workflow-schedule.module.ts +67 -67
  392. package/src/resources/dev.properties.yaml +31 -31
  393. package/src/resources/local.properties.yaml +27 -27
  394. package/src/resources/properties.module.ts +12 -12
  395. package/src/resources/properties.yaml.ts +11 -11
  396. package/src/resources/uat.properties.yaml +31 -31
  397. package/src/table.config.ts +130 -130
  398. package/src/utils/dto/excel-data.dto.ts +14 -14
  399. package/src/utils/dto/excelsheet-data.dto.ts +5 -5
  400. package/src/utils/service/base64util.service.ts +18 -18
  401. package/src/utils/service/clockIDGenUtil.service.ts +21 -21
  402. package/src/utils/service/codeGenerator.service.ts +22 -22
  403. package/src/utils/service/dateUtil.service.ts +17 -17
  404. package/src/utils/service/encryptUtil.service.ts +97 -97
  405. package/src/utils/service/excel-helper.service.ts +72 -72
  406. package/src/utils/service/excelUtil.service.ts +15 -15
  407. package/src/utils/service/file-util.service.ts +11 -11
  408. package/src/utils/service/json-util.service.ts +23 -23
  409. package/src/utils/service/loggingUtil.service.ts +88 -88
  410. package/src/utils/service/reflection-helper.service.ts +62 -62
  411. package/src/utils/service/wbsCodeGen.service.ts +8 -8
  412. package/src/utils/utils.module.ts +27 -27
  413. package/tsconfig.build.json +4 -4
  414. package/tsconfig.json +24 -24
  415. package/.claude/settings.local.json +0 -26
  416. package/.idea/250218_nodejs_core.iml +0 -9
  417. package/.idea/codeStyles/Project.xml +0 -59
  418. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  419. package/.idea/copilot.data.migration.agent.xml +0 -6
  420. package/.idea/copilot.data.migration.ask.xml +0 -6
  421. package/.idea/copilot.data.migration.ask2agent.xml +0 -6
  422. package/.idea/copilot.data.migration.edit.xml +0 -6
  423. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  424. package/.idea/misc.xml +0 -6
  425. package/.idea/modules.xml +0 -8
  426. package/.idea/prettier.xml +0 -6
  427. package/.idea/vcs.xml +0 -6
  428. 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: '*/1 * * * *',
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: '*/1 * * * *',
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
+ }