rez_core 5.0.86 → 5.0.87

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 (438) hide show
  1. package/.claude/settings.local.json +26 -0
  2. package/.idea/250218_nodejs_core.iml +8 -11
  3. package/.idea/codeStyles/Project.xml +58 -58
  4. package/.idea/codeStyles/codeStyleConfig.xml +4 -4
  5. package/.idea/copilot.data.migration.agent.xml +6 -0
  6. package/.idea/copilot.data.migration.ask.xml +6 -0
  7. package/.idea/copilot.data.migration.ask2agent.xml +6 -0
  8. package/.idea/copilot.data.migration.edit.xml +6 -0
  9. package/.idea/inspectionProfiles/Project_Default.xml +1 -1
  10. package/.idea/misc.xml +6 -0
  11. package/.idea/modules.xml +7 -7
  12. package/.idea/prettier.xml +5 -5
  13. package/.idea/vcs.xml +5 -5
  14. package/.prettierrc +3 -3
  15. package/README.md +99 -99
  16. package/dist/module/auth/guards/role.guard.js +3 -3
  17. package/dist/module/enterprise/repository/school.repository.d.ts +3 -3
  18. package/dist/module/enterprise/repository/school.repository.js +56 -70
  19. package/dist/module/enterprise/repository/school.repository.js.map +1 -1
  20. package/dist/module/filter/service/filter.service.js +20 -20
  21. package/dist/module/integration/examples/usage.example.js +9 -9
  22. package/dist/module/mapper/service/field-mapper.service.d.ts +1 -3
  23. package/dist/module/mapper/service/field-mapper.service.js +10 -10
  24. package/dist/module/mapper/service/field-mapper.service.js.map +1 -1
  25. package/dist/module/meta/controller/meta.controller.d.ts +4 -1
  26. package/dist/module/meta/repository/attribute-master.repository.js +8 -8
  27. package/dist/module/meta/repository/entity-attribute-update.repository.d.ts +5 -3
  28. package/dist/module/meta/repository/entity-attribute-update.repository.js +19 -13
  29. package/dist/module/meta/repository/entity-attribute-update.repository.js.map +1 -1
  30. package/dist/module/meta/repository/entity-master.repository.d.ts +8 -4
  31. package/dist/module/meta/repository/entity-master.repository.js +17 -14
  32. package/dist/module/meta/repository/entity-master.repository.js.map +1 -1
  33. package/dist/module/meta/service/entity-dynamic.service.js +21 -21
  34. package/dist/module/meta/service/entity-dynamic.service.js.map +1 -1
  35. package/dist/module/meta/service/entity-list.service.js +3 -3
  36. package/dist/module/meta/service/entity-master.service.d.ts +4 -1
  37. package/dist/module/meta/service/entity-relation.service.js +9 -9
  38. package/dist/module/meta/service/entity-service-impl.service.js +3 -3
  39. package/dist/module/meta/service/media-data.service.js +6 -6
  40. package/dist/module/meta/service/resolver.service.d.ts +5 -3
  41. package/dist/module/meta/service/resolver.service.js +40 -49
  42. package/dist/module/meta/service/resolver.service.js.map +1 -1
  43. package/dist/module/module/repository/menu.repository.js +5 -5
  44. package/dist/module/module/repository/menu.repository.js.map +1 -1
  45. package/dist/module/notification/service/notification.service.js +10 -10
  46. package/dist/module/user/controller/login.controller.js +18 -18
  47. package/dist/module/user/service/user-session.service.d.ts +8 -5
  48. package/dist/module/user/service/user-session.service.js +45 -24
  49. package/dist/module/user/service/user-session.service.js.map +1 -1
  50. package/dist/module/workflow/controller/action-template-mapping.controller.d.ts +1 -1
  51. package/dist/module/workflow/repository/action.repository.js +12 -12
  52. package/dist/module/workflow/repository/comm-template.repository.js +3 -3
  53. package/dist/module/workflow/repository/form-master.repository.js +2 -2
  54. package/dist/module/workflow/repository/stage-group.repository.js +20 -20
  55. package/dist/module/workflow/repository/stage.repository.js +8 -8
  56. package/dist/module/workflow/repository/stage.repository.js.map +1 -1
  57. package/dist/module/workflow/service/action-template-mapping.service.d.ts +3 -4
  58. package/dist/module/workflow/service/action-template-mapping.service.js +43 -33
  59. package/dist/module/workflow/service/action-template-mapping.service.js.map +1 -1
  60. package/dist/module/workflow/service/action.service.js +7 -7
  61. package/dist/module/workflow/service/entity-modification.service.js +2 -2
  62. package/dist/module/workflow/service/populate-workflow.service.js.map +1 -1
  63. package/dist/module/workflow/service/stage-group.service.js +2 -2
  64. package/dist/module/workflow/service/stage.service.js +2 -2
  65. package/dist/module/workflow/service/task.service.js +18 -18
  66. package/dist/module/workflow/service/workflow-list-master.service.js +15 -15
  67. package/dist/module/workflow/service/workflow-meta.service.js +26 -26
  68. package/dist/module/workflow/service/workflow-meta.service.js.map +1 -1
  69. package/dist/module/workflow-automation/service/schedule-handler.service.js +9 -9
  70. package/dist/module/workflow-automation/service/workflow-automation-engine.service.js.map +1 -1
  71. package/dist/module/workflow-schedule/processors/schedule.processor.js +4 -4
  72. package/dist/module/workflow-schedule/service/workflow-schedule.service.js +9 -9
  73. package/dist/tsconfig.build.tsbuildinfo +1 -1
  74. package/dist/utils/service/reflection-helper.service.js +2 -2
  75. package/docs/modules/event-driven-integration-design.md +91 -91
  76. package/docs/modules/integration.md +250 -250
  77. package/eslint.config.mjs +34 -34
  78. package/nest-cli.json +14 -14
  79. package/package.json +125 -125
  80. package/server.log +850 -0
  81. package/src/app.controller.ts +12 -12
  82. package/src/app.module.ts +66 -66
  83. package/src/app.service.ts +8 -8
  84. package/src/config/bull.config.ts +69 -69
  85. package/src/config/config.module.ts +17 -17
  86. package/src/config/database.config.ts +48 -48
  87. package/src/constant/global.constant.ts +67 -67
  88. package/src/core.module.ts +91 -91
  89. package/src/decorators/roles.decorator.ts +7 -7
  90. package/src/dtos/response.dto.ts +6 -6
  91. package/src/dtos/response.ts +5 -5
  92. package/src/index.ts +1 -1
  93. package/src/module/auth/auth.module.ts +49 -49
  94. package/src/module/auth/controller/auth.controller.ts +28 -28
  95. package/src/module/auth/guards/google-auth.guard.ts +9 -9
  96. package/src/module/auth/guards/jwt.guard.ts +22 -22
  97. package/src/module/auth/guards/role.guard.ts +68 -68
  98. package/src/module/auth/services/auth.service.ts +56 -56
  99. package/src/module/auth/services/jwt.service.ts +11 -11
  100. package/src/module/auth/strategies/google.strategy.ts +54 -54
  101. package/src/module/auth/strategies/jwt.strategy.ts +58 -58
  102. package/src/module/auth/strategies/local.strategy.ts +13 -13
  103. package/src/module/dashboard/controller/dashboard.controller.ts +36 -36
  104. package/src/module/dashboard/dashboard.module.ts +21 -21
  105. package/src/module/dashboard/entity/dashboard_page_data.entity.ts +27 -27
  106. package/src/module/dashboard/entity/widget_master.entity.ts +18 -18
  107. package/src/module/dashboard/repository/dashboard.repository.ts +51 -51
  108. package/src/module/dashboard/service/dashboard.service.ts +73 -73
  109. package/src/module/enterprise/controller/organization.controller.ts +36 -36
  110. package/src/module/enterprise/enterprise.module.ts +30 -30
  111. package/src/module/enterprise/entity/enterprise.entity.ts +37 -37
  112. package/src/module/enterprise/entity/organization-app-mapping.entity.ts +13 -13
  113. package/src/module/enterprise/entity/organization.entity.ts +92 -92
  114. package/src/module/enterprise/repository/enterprise.repository.ts +31 -31
  115. package/src/module/enterprise/repository/organization.repository.ts +26 -26
  116. package/src/module/enterprise/repository/school.repository.ts +272 -278
  117. package/src/module/enterprise/service/brand.service.ts +5 -5
  118. package/src/module/enterprise/service/enterprise.service.ts +16 -16
  119. package/src/module/enterprise/service/organization-app-mapping.service.ts +4 -4
  120. package/src/module/enterprise/service/organization.service.ts +145 -145
  121. package/src/module/entity_json/controller/entity_json.controller.ts +47 -47
  122. package/src/module/entity_json/entity/entityJson.entity.ts +39 -39
  123. package/src/module/entity_json/entity_json.module.ts +18 -18
  124. package/src/module/entity_json/service/entityJson.repository.ts +37 -37
  125. package/src/module/entity_json/service/entity_json.service.ts +234 -234
  126. package/src/module/filter/controller/filter.controller.ts +84 -84
  127. package/src/module/filter/dto/filter-request.dto.ts +38 -38
  128. package/src/module/filter/entity/saved-filter-detail.entity.ts +41 -41
  129. package/src/module/filter/entity/saved-filter-master.entity.ts +23 -23
  130. package/src/module/filter/filter.module.ts +33 -33
  131. package/src/module/filter/repository/saved-filter.repository.ts +168 -168
  132. package/src/module/filter/repository/saved.filter-detail.repository.ts +19 -19
  133. package/src/module/filter/service/filter-evaluator.service.ts +82 -82
  134. package/src/module/filter/service/filter.service.ts +1304 -1304
  135. package/src/module/filter/service/saved-filter.service.ts +170 -170
  136. package/src/module/ics/controller/ics.controller.ts +21 -21
  137. package/src/module/ics/dto/ics.dto.ts +55 -55
  138. package/src/module/ics/ics.module.ts +13 -13
  139. package/src/module/ics/service/ics.service.ts +57 -57
  140. package/src/module/integration/controller/calender-event.controller.ts +31 -31
  141. package/src/module/integration/controller/integration.controller.ts +662 -662
  142. package/src/module/integration/controller/wrapper.controller.ts +37 -37
  143. package/src/module/integration/dto/create-config.dto.ts +526 -526
  144. package/src/module/integration/entity/integration-config.entity.ts +112 -112
  145. package/src/module/integration/entity/integration-entity-mapper.entity.ts +14 -14
  146. package/src/module/integration/entity/integration-source.entity.ts +17 -17
  147. package/src/module/integration/entity/user-integration.entity.ts +71 -71
  148. package/src/module/integration/examples/usage.example.ts +338 -338
  149. package/src/module/integration/factories/base.factory.ts +7 -7
  150. package/src/module/integration/factories/email.factory.ts +49 -49
  151. package/src/module/integration/factories/integration.factory.ts +121 -121
  152. package/src/module/integration/factories/sms.factory.ts +51 -51
  153. package/src/module/integration/factories/telephone.factory.ts +41 -41
  154. package/src/module/integration/factories/whatsapp.factory.ts +56 -56
  155. package/src/module/integration/integration.module.ts +110 -110
  156. package/src/module/integration/service/calendar-event.service.ts +118 -118
  157. package/src/module/integration/service/integration-entity-mapper.service.ts +17 -17
  158. package/src/module/integration/service/integration-queue.service.ts +229 -229
  159. package/src/module/integration/service/integration.service.ts +2634 -2634
  160. package/src/module/integration/service/oauth.service.ts +224 -224
  161. package/src/module/integration/service/wrapper.service.ts +716 -716
  162. package/src/module/integration/strategies/email/gmail-api.strategy.ts +280 -280
  163. package/src/module/integration/strategies/email/outlook-api.strategy.ts +44 -44
  164. package/src/module/integration/strategies/email/outlook.strategy.ts +64 -64
  165. package/src/module/integration/strategies/email/sendgrid-api.strategy.ts +260 -260
  166. package/src/module/integration/strategies/integration.strategy.ts +97 -97
  167. package/src/module/integration/strategies/sms/gupshup-sms.strategy.ts +146 -146
  168. package/src/module/integration/strategies/sms/msg91-sms.strategy.ts +164 -164
  169. package/src/module/integration/strategies/sms/tubelight-sms.strategy.ts +163 -163
  170. package/src/module/integration/strategies/telephone/ozonetel-voice.strategy.ts +238 -238
  171. package/src/module/integration/strategies/telephone/tubelight-voice.strategy.ts +210 -210
  172. package/src/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.ts +359 -359
  173. package/src/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.ts +372 -372
  174. package/src/module/integration/strategies/whatsapp/whatsapp-cloud.strategy.ts +403 -403
  175. package/src/module/integration/strategies/whatsapp/whatsapp.strategy.ts +57 -57
  176. package/src/module/layout/controller/layout.controller.ts +47 -47
  177. package/src/module/layout/entity/header-items.entity.ts +28 -28
  178. package/src/module/layout/entity/header-section.entity.ts +19 -19
  179. package/src/module/layout/layout.module.ts +21 -21
  180. package/src/module/layout/repository/header-items.repository.ts +18 -18
  181. package/src/module/layout/repository/header-section.repository.ts +22 -22
  182. package/src/module/layout/service/header-section.service.ts +25 -25
  183. package/src/module/layout_preference/controller/layout_preference.controller.ts +73 -73
  184. package/src/module/layout_preference/entity/layout_preference.entity.ts +28 -28
  185. package/src/module/layout_preference/layout_preference.module.ts +22 -22
  186. package/src/module/layout_preference/repository/layout_preference.repository.ts +65 -65
  187. package/src/module/layout_preference/service/layout_preference.service.ts +191 -191
  188. package/src/module/lead/controller/lead.controller.ts +30 -30
  189. package/src/module/lead/lead.module.ts +14 -14
  190. package/src/module/lead/repository/lead.repository.ts +41 -41
  191. package/src/module/lead/service/lead.service.ts +54 -54
  192. package/src/module/linked_attributes/controller/linked_attributes.controller.ts +37 -37
  193. package/src/module/linked_attributes/entity/linked_attribute.entity.ts +51 -51
  194. package/src/module/linked_attributes/linked_attributes.module.ts +16 -16
  195. package/src/module/linked_attributes/repository/linked_attribute.repository.ts +12 -12
  196. package/src/module/linked_attributes/service/linked_attributes.service.ts +75 -75
  197. package/src/module/listmaster/controller/list-master.controller.ts +230 -230
  198. package/src/module/listmaster/entity/list-master-items.entity.ts +43 -43
  199. package/src/module/listmaster/entity/list-master.entity.ts +33 -33
  200. package/src/module/listmaster/listmaster.module.ts +46 -46
  201. package/src/module/listmaster/repository/list-master-items.repository.ts +173 -173
  202. package/src/module/listmaster/repository/list-master.repository.ts +56 -56
  203. package/src/module/listmaster/service/list-master-engine.ts +19 -19
  204. package/src/module/listmaster/service/list-master-extension.interface.ts +4 -4
  205. package/src/module/listmaster/service/list-master-item.service.ts +281 -281
  206. package/src/module/listmaster/service/list-master-registry.ts +15 -15
  207. package/src/module/listmaster/service/list-master.service.ts +535 -535
  208. package/src/module/mapper/controller/field-mapper.controller.ts +76 -76
  209. package/src/module/mapper/controller/mapper.controller.ts +20 -20
  210. package/src/module/mapper/dto/field-mapper.dto.ts +14 -14
  211. package/src/module/mapper/entity/field-lovs.entity.ts +19 -19
  212. package/src/module/mapper/entity/field-mapper.entity.ts +53 -53
  213. package/src/module/mapper/entity/mapper.entity.ts +16 -16
  214. package/src/module/mapper/mapper.module.ts +35 -35
  215. package/src/module/mapper/repository/field-lovs.repository.ts +35 -35
  216. package/src/module/mapper/repository/field-mapper.repository.ts +42 -42
  217. package/src/module/mapper/repository/mapper.repository.ts +32 -32
  218. package/src/module/mapper/service/field-mapper.service.ts +269 -271
  219. package/src/module/mapper/service/mapper.service.ts +81 -81
  220. package/src/module/master/controller/master.controller.ts +74 -74
  221. package/src/module/master/service/master.service.ts +483 -483
  222. package/src/module/meta/controller/app-master.controller.ts +38 -38
  223. package/src/module/meta/controller/attribute-master.controller.ts +84 -84
  224. package/src/module/meta/controller/entity-dynamic.controller.ts +125 -125
  225. package/src/module/meta/controller/entity-master.controller.ts +41 -41
  226. package/src/module/meta/controller/entity-relation.controller.ts +36 -36
  227. package/src/module/meta/controller/entity.controller.ts +392 -392
  228. package/src/module/meta/controller/entity.public.controller.ts +75 -75
  229. package/src/module/meta/controller/media.controller.ts +107 -107
  230. package/src/module/meta/controller/meta.controller.ts +96 -96
  231. package/src/module/meta/controller/view-master.controller.ts +86 -86
  232. package/src/module/meta/dto/entity-list-data.dto.ts +6 -6
  233. package/src/module/meta/dto/entity-tab.dto.ts +4 -4
  234. package/src/module/meta/dto/entity-table.dto.ts +9 -9
  235. package/src/module/meta/entity/app-master.entity.ts +34 -34
  236. package/src/module/meta/entity/attribute-master.entity.ts +92 -92
  237. package/src/module/meta/entity/base-entity.entity.ts +75 -75
  238. package/src/module/meta/entity/entity-master.entity.ts +85 -85
  239. package/src/module/meta/entity/entity-relation-data.entity.ts +29 -29
  240. package/src/module/meta/entity/entity-relation.entity.ts +23 -23
  241. package/src/module/meta/entity/entity-table-column.entity.ts +61 -61
  242. package/src/module/meta/entity/entity-table.entity.ts +50 -50
  243. package/src/module/meta/entity/media-data.entity.ts +32 -32
  244. package/src/module/meta/entity/preference.entity.ts +62 -62
  245. package/src/module/meta/entity/view-master.entity.ts +41 -41
  246. package/src/module/meta/entity.module.ts +166 -166
  247. package/src/module/meta/repository/app-master.repository.ts +20 -20
  248. package/src/module/meta/repository/attribute-master.repository.ts +156 -156
  249. package/src/module/meta/repository/entity-attribute-update.repository.ts +48 -44
  250. package/src/module/meta/repository/entity-master.repository.ts +109 -111
  251. package/src/module/meta/repository/entity-table-column.repository.ts +39 -39
  252. package/src/module/meta/repository/entity-table.repository.ts +53 -53
  253. package/src/module/meta/repository/media-data.repository.ts +50 -50
  254. package/src/module/meta/repository/preference.repository.ts +20 -20
  255. package/src/module/meta/repository/user-app-mapping.repository.ts +28 -28
  256. package/src/module/meta/repository/view-master.repository.ts +42 -42
  257. package/src/module/meta/service/app-master.service.ts +37 -37
  258. package/src/module/meta/service/attribute-master.service.ts +130 -130
  259. package/src/module/meta/service/common.service.ts +9 -9
  260. package/src/module/meta/service/entity-attribute-update.service.ts +28 -28
  261. package/src/module/meta/service/entity-dynamic.service.ts +810 -846
  262. package/src/module/meta/service/entity-list.service.ts +205 -205
  263. package/src/module/meta/service/entity-master.service.ts +171 -171
  264. package/src/module/meta/service/entity-realation-data.service.ts +9 -9
  265. package/src/module/meta/service/entity-relation.service.ts +87 -87
  266. package/src/module/meta/service/entity-service-impl.service.ts +525 -525
  267. package/src/module/meta/service/entity-table-column.service.ts +39 -39
  268. package/src/module/meta/service/entity-table.service.ts +150 -150
  269. package/src/module/meta/service/entity-validation.service.ts +187 -187
  270. package/src/module/meta/service/entity.service.ts +67 -67
  271. package/src/module/meta/service/field-group.service.ts +103 -103
  272. package/src/module/meta/service/media-data.service.ts +510 -510
  273. package/src/module/meta/service/populate-meta.service.ts +222 -222
  274. package/src/module/meta/service/preference.service.ts +16 -16
  275. package/src/module/meta/service/resolver.service.ts +292 -316
  276. package/src/module/meta/service/section-master.service.ts +104 -104
  277. package/src/module/meta/service/update-form-json.service.ts +22 -22
  278. package/src/module/meta/service/user-app-mapping.service.ts +17 -17
  279. package/src/module/meta/service/view-master.service.ts +127 -127
  280. package/src/module/microservice-client/microservice-clients.module.ts +13 -13
  281. package/src/module/microservice-client/service/microservice-client-factory.ts +37 -37
  282. package/src/module/microservice-client/service/microservice-clients.ts +4 -4
  283. package/src/module/module/controller/menu.controller.ts +15 -15
  284. package/src/module/module/controller/module-access.controller.ts +134 -134
  285. package/src/module/module/entity/menu.entity.ts +43 -43
  286. package/src/module/module/entity/module-access.entity.ts +25 -25
  287. package/src/module/module/entity/module-action.entity.ts +17 -17
  288. package/src/module/module/entity/module.entity.ts +52 -52
  289. package/src/module/module/module.module.ts +42 -42
  290. package/src/module/module/repository/menu.repository.ts +184 -184
  291. package/src/module/module/repository/module-access.repository.ts +344 -344
  292. package/src/module/module/service/menu.service.ts +82 -82
  293. package/src/module/module/service/module-access.service.ts +195 -195
  294. package/src/module/notification/controller/notification.controller.ts +58 -58
  295. package/src/module/notification/controller/otp.controller.ts +117 -117
  296. package/src/module/notification/entity/notification.entity.ts +26 -26
  297. package/src/module/notification/entity/otp.entity.ts +28 -28
  298. package/src/module/notification/firebase-admin.config.ts +22 -22
  299. package/src/module/notification/notification.module.ts +69 -69
  300. package/src/module/notification/repository/otp.repository.ts +27 -27
  301. package/src/module/notification/service/email.service.ts +127 -127
  302. package/src/module/notification/service/notification.service.ts +160 -160
  303. package/src/module/notification/service/otp.service.ts +133 -133
  304. package/src/module/third-party-module/entity/third-party-api-registry.entity.ts +52 -52
  305. package/src/module/third-party-module/repository/third-party-api-registry.repository.ts +20 -20
  306. package/src/module/third-party-module/service/api-registry.service.ts +13 -13
  307. package/src/module/third-party-module/third-party.module.ts +12 -12
  308. package/src/module/user/controller/login.controller.ts +198 -198
  309. package/src/module/user/controller/user.controller.ts +40 -40
  310. package/src/module/user/dto/create-user.dto.ts +62 -62
  311. package/src/module/user/dto/update-user.dto.ts +4 -4
  312. package/src/module/user/entity/role.entity.ts +33 -33
  313. package/src/module/user/entity/user-role-mapping.entity.ts +38 -38
  314. package/src/module/user/entity/user-session.entity.ts +73 -73
  315. package/src/module/user/entity/user.entity.ts +59 -59
  316. package/src/module/user/repository/role.repository.ts +96 -96
  317. package/src/module/user/repository/user-role-mapping.repository.ts +126 -126
  318. package/src/module/user/repository/user.repository.ts +50 -50
  319. package/src/module/user/repository/userSession.repository.ts +33 -33
  320. package/src/module/user/service/login.service.ts +326 -326
  321. package/src/module/user/service/role.service.ts +197 -197
  322. package/src/module/user/service/user-role-mapping.service.ts +98 -98
  323. package/src/module/user/service/user-session.service.ts +177 -168
  324. package/src/module/user/service/user.service.ts +368 -368
  325. package/src/module/user/user.module.ts +65 -65
  326. package/src/module/workflow/controller/action-category.controller.ts +54 -54
  327. package/src/module/workflow/controller/action-resource-mapping.controller.ts +23 -23
  328. package/src/module/workflow/controller/action-template-mapping.controller.ts +35 -35
  329. package/src/module/workflow/controller/action.controller.ts +111 -111
  330. package/src/module/workflow/controller/activity-log.controller.ts +55 -55
  331. package/src/module/workflow/controller/comm-template.controller.ts +43 -43
  332. package/src/module/workflow/controller/entity-modification.controller.ts +35 -35
  333. package/src/module/workflow/controller/form-master.controller.ts +43 -43
  334. package/src/module/workflow/controller/stage-group.controller.ts +48 -48
  335. package/src/module/workflow/controller/stage.controller.ts +50 -50
  336. package/src/module/workflow/controller/task.controller.ts +77 -77
  337. package/src/module/workflow/controller/workflow-list-master.controller.ts +44 -44
  338. package/src/module/workflow/controller/workflow-meta.controller.ts +80 -80
  339. package/src/module/workflow/controller/workflow.controller.ts +67 -67
  340. package/src/module/workflow/entity/action-category.entity.ts +38 -38
  341. package/src/module/workflow/entity/action-data.entity.ts +55 -55
  342. package/src/module/workflow/entity/action-resources-mapping.entity.ts +29 -29
  343. package/src/module/workflow/entity/action-template-mapping.entity.ts +17 -17
  344. package/src/module/workflow/entity/action.entity.ts +53 -53
  345. package/src/module/workflow/entity/activity-log.entity.ts +43 -43
  346. package/src/module/workflow/entity/comm-template.entity.ts +43 -43
  347. package/src/module/workflow/entity/entity-modification.entity.ts +38 -38
  348. package/src/module/workflow/entity/form.entity.ts +25 -25
  349. package/src/module/workflow/entity/stage-action-mapping.entity.ts +17 -17
  350. package/src/module/workflow/entity/stage-group.entity.ts +23 -23
  351. package/src/module/workflow/entity/stage-movement-data.entity.ts +38 -38
  352. package/src/module/workflow/entity/stage.entity.ts +20 -20
  353. package/src/module/workflow/entity/task-data.entity.ts +88 -88
  354. package/src/module/workflow/entity/template-attach-mapper.entity.ts +30 -30
  355. package/src/module/workflow/entity/workflow-data.entity.ts +11 -11
  356. package/src/module/workflow/entity/workflow-level-mapping.entity.ts +18 -18
  357. package/src/module/workflow/entity/workflow.entity.ts +20 -20
  358. package/src/module/workflow/repository/action-category.repository.ts +79 -79
  359. package/src/module/workflow/repository/action-data.repository.ts +339 -339
  360. package/src/module/workflow/repository/action.repository.ts +341 -341
  361. package/src/module/workflow/repository/activity-log.repository.ts +148 -148
  362. package/src/module/workflow/repository/comm-template.repository.ts +151 -151
  363. package/src/module/workflow/repository/form-master.repository.ts +59 -59
  364. package/src/module/workflow/repository/stage-group.repository.ts +197 -197
  365. package/src/module/workflow/repository/stage-movement.repository.ts +253 -253
  366. package/src/module/workflow/repository/stage.repository.ts +160 -172
  367. package/src/module/workflow/repository/task.repository.ts +151 -151
  368. package/src/module/workflow/repository/workflow.repository.ts +42 -42
  369. package/src/module/workflow/service/action-category.service.ts +33 -33
  370. package/src/module/workflow/service/action-data.service.ts +62 -62
  371. package/src/module/workflow/service/action-resources-mapping.service.ts +10 -10
  372. package/src/module/workflow/service/action-template-mapping.service.ts +131 -131
  373. package/src/module/workflow/service/action.service.ts +279 -279
  374. package/src/module/workflow/service/activity-log.service.ts +107 -107
  375. package/src/module/workflow/service/comm-template.service.ts +180 -180
  376. package/src/module/workflow/service/entity-modification.service.ts +61 -61
  377. package/src/module/workflow/service/form-master.service.ts +35 -35
  378. package/src/module/workflow/service/populate-workflow.service.ts +320 -333
  379. package/src/module/workflow/service/stage-action-mapping.service.ts +5 -5
  380. package/src/module/workflow/service/stage-group.service.ts +342 -342
  381. package/src/module/workflow/service/stage.service.ts +199 -199
  382. package/src/module/workflow/service/task.service.ts +549 -549
  383. package/src/module/workflow/service/workflow-list-master.service.ts +60 -60
  384. package/src/module/workflow/service/workflow-meta.service.ts +635 -653
  385. package/src/module/workflow/service/workflow.service.ts +209 -209
  386. package/src/module/workflow/workflow.module.ts +180 -180
  387. package/src/module/workflow-automation/SCHEDULING_GUIDE.md +145 -145
  388. package/src/module/workflow-automation/controller/workflow-automation.controller.ts +43 -43
  389. package/src/module/workflow-automation/entity/workflow-automation-action.entity.ts +26 -26
  390. package/src/module/workflow-automation/entity/workflow-automation.entity.ts +40 -40
  391. package/src/module/workflow-automation/interface/action.decorator.ts +7 -7
  392. package/src/module/workflow-automation/interface/action.interface.ts +5 -5
  393. package/src/module/workflow-automation/service/action-registery.service.ts +35 -35
  394. package/src/module/workflow-automation/service/schedule-handler.service.ts +168 -168
  395. package/src/module/workflow-automation/service/workflow-automation-engine.service.ts +219 -224
  396. package/src/module/workflow-automation/service/workflow-automation.service.ts +515 -515
  397. package/src/module/workflow-automation/workflow-automation.module.ts +54 -54
  398. package/src/module/workflow-schedule/INSTALLATION.md +244 -244
  399. package/src/module/workflow-schedule/MULTI_PROJECT_GUIDE.md +196 -196
  400. package/src/module/workflow-schedule/README.md +422 -422
  401. package/src/module/workflow-schedule/constants/schedule.constants.ts +48 -48
  402. package/src/module/workflow-schedule/controller/workflow-schedule.controller.ts +255 -255
  403. package/src/module/workflow-schedule/docs/CLAUDE_CODE_GUIDE.md +510 -510
  404. package/src/module/workflow-schedule/docs/CLAUDE_CODE_PROMPT.md +362 -362
  405. package/src/module/workflow-schedule/docs/RUN_CLAUDE_CODE.sh +68 -68
  406. package/src/module/workflow-schedule/dto/create-schedule.dto.ts +147 -147
  407. package/src/module/workflow-schedule/dto/get-execution-logs.dto.ts +119 -119
  408. package/src/module/workflow-schedule/dto/update-schedule.dto.ts +96 -96
  409. package/src/module/workflow-schedule/entities/scheduled-workflow.entity.ts +148 -148
  410. package/src/module/workflow-schedule/entities/workflow-execution-log.entity.ts +154 -154
  411. package/src/module/workflow-schedule/interfaces/schedule-job-data.interface.ts +53 -53
  412. package/src/module/workflow-schedule/interfaces/workflow-schedule-options.interface.ts +12 -12
  413. package/src/module/workflow-schedule/processors/schedule.processor.ts +584 -584
  414. package/src/module/workflow-schedule/service/workflow-schedule.service.ts +600 -600
  415. package/src/module/workflow-schedule/workflow-schedule.module.ts +67 -67
  416. package/src/resources/dev.properties.yaml +31 -31
  417. package/src/resources/local.properties.yaml +27 -27
  418. package/src/resources/properties.module.ts +12 -12
  419. package/src/resources/properties.yaml.ts +11 -11
  420. package/src/resources/uat.properties.yaml +31 -31
  421. package/src/table.config.ts +133 -133
  422. package/src/utils/dto/excel-data.dto.ts +14 -14
  423. package/src/utils/dto/excelsheet-data.dto.ts +5 -5
  424. package/src/utils/service/base64util.service.ts +18 -18
  425. package/src/utils/service/clockIDGenUtil.service.ts +21 -21
  426. package/src/utils/service/codeGenerator.service.ts +22 -22
  427. package/src/utils/service/dateUtil.service.ts +17 -17
  428. package/src/utils/service/encryptUtil.service.ts +97 -97
  429. package/src/utils/service/excel-helper.service.ts +72 -72
  430. package/src/utils/service/excelUtil.service.ts +15 -15
  431. package/src/utils/service/file-util.service.ts +11 -11
  432. package/src/utils/service/json-util.service.ts +23 -23
  433. package/src/utils/service/loggingUtil.service.ts +88 -88
  434. package/src/utils/service/reflection-helper.service.ts +62 -62
  435. package/src/utils/service/wbsCodeGen.service.ts +8 -8
  436. package/src/utils/utils.module.ts +27 -27
  437. package/tsconfig.build.json +4 -4
  438. package/tsconfig.json +24 -24
@@ -1,846 +1,810 @@
1
- import { BadRequestException, Injectable } from '@nestjs/common';
2
- import { STATUS_ACTIVE } from 'src/constant/global.constant';
3
- import { EntityManager, In } from 'typeorm';
4
- import { UserData } from 'src/module/user/entity/user.entity';
5
- import { MediaDataService } from './media-data.service';
6
- import { ResolverService } from './resolver.service';
7
- import { EntityMasterRepository } from '../repository/entity-master.repository';
8
- import { ReflectionHelper } from '../../../utils/service/reflection-helper.service';
9
-
10
- @Injectable()
11
- export class EntityDynamicService {
12
- constructor(
13
- private readonly entityManager: EntityManager,
14
- private readonly mediaDataService: MediaDataService,
15
- private readonly resolverService: ResolverService,
16
- private readonly entityMasterRepo: EntityMasterRepository,
17
- private readonly reflectionHelper: ReflectionHelper,
18
- ) {}
19
-
20
- // -----------------------------
21
- async createEntity(
22
- entityType: string,
23
- entityData: Record<string, any>,
24
- loggedInUser: any,
25
- mainID?: number,
26
- ): Promise<any> {
27
- const organizationId = loggedInUser.organization_id;
28
-
29
- const tableName = await this.getTableName(entityType, organizationId);
30
- const validAttributes = await this.getAttributeCodes(
31
- entityType,
32
- organizationId,
33
- );
34
-
35
- // -------------------------------------------------------
36
- // AUTO fields
37
- // -------------------------------------------------------
38
- entityData.created_date = new Date();
39
-
40
- if (loggedInUser) {
41
- entityData.created_by = loggedInUser.id;
42
-
43
- if (!entityData.organization_id)
44
- entityData.organization_id = loggedInUser.organization_id;
45
-
46
- if (!entityData.enterprise_id)
47
- entityData.enterprise_id = loggedInUser.enterprise_id;
48
-
49
- if (!entityData.level_type)
50
- entityData.level_type = loggedInUser.level_type;
51
-
52
- if (!entityData.level_id) entityData.level_id = loggedInUser.level_id;
53
-
54
- if (!entityData.entity_type) entityData.entity_type = entityType;
55
- }
56
-
57
- // -------------------------------------------------------
58
- // STATUS
59
- // -------------------------------------------------------
60
- const listMasterItemsRepo =
61
- this.reflectionHelper.getRepoService('ListMasterItems');
62
- const statusList = listMasterItemsRepo.find({
63
- where: {
64
- code: STATUS_ACTIVE,
65
- organization_id: organizationId,
66
- },
67
- });
68
-
69
- if (!entityData.status) entityData.status = statusList[0]?.id;
70
-
71
- // -------------------------------------------------------
72
- // AUTO-CODE GENERATION (POSTGRES SAFE)
73
- // -------------------------------------------------------
74
- if (!entityData.code && entityData.entity_type) {
75
- // Extract integer suffix
76
- const result = await this.entityManager.query(
77
- `
78
- SELECT MAX(id) AS max_seq_no
79
- FROM ${tableName}
80
- WHERE entity_type = $1
81
- `,
82
- [entityData.entity_type],
83
- );
84
-
85
- let maxSeq = Number(result?.[0]?.max_seq_no) || 0;
86
- maxSeq++;
87
- entityData.code = `${entityData.entity_type}${maxSeq}`;
88
- }
89
-
90
- // -------------------------------------------------------
91
- // Parent ID
92
- // -------------------------------------------------------
93
- if (mainID) {
94
- entityData.parent_id = mainID;
95
- }
96
-
97
- // -------------------------------------------------------
98
- // BYPASS COLUMNS
99
- // -------------------------------------------------------
100
- const bypassColumns = [
101
- 'created_date',
102
- 'created_by',
103
- 'organization_id',
104
- 'enterprise_id',
105
- 'level_type',
106
- 'level_id',
107
- 'status',
108
- 'entity_type',
109
- 'code',
110
- 'parent_id',
111
- ];
112
-
113
- for (const col of bypassColumns) {
114
- if (!validAttributes.some((a) => a.attribute_key === col)) {
115
- validAttributes.push({
116
- attribute_key: col,
117
- is_hidden: false,
118
- db_datatype: 'text',
119
- element_type: 'text',
120
- });
121
- }
122
- }
123
-
124
- // -------------------------------------------------------
125
- // BUILD INSERT QUERY (POSTGRES FORMAT)
126
- // -------------------------------------------------------
127
- const columns: string[] = [];
128
- const values: any[] = [];
129
- let idx = 1;
130
- const placeholders: string[] = [];
131
-
132
- for (const attr of validAttributes) {
133
- if (attr.attribute_key === 'id') continue;
134
-
135
- columns.push(attr.attribute_key);
136
- values.push(entityData[attr.attribute_key] ?? null);
137
- placeholders.push(`$${idx++}`);
138
- }
139
-
140
- const colList = columns.map((c) => `"${c}"`).join(', ');
141
- const placeholderList = placeholders.join(', ');
142
-
143
- const sql = `
144
- INSERT INTO ${tableName} (${colList})
145
- VALUES (${placeholderList}) RETURNING id
146
- `;
147
-
148
- const result = await this.entityManager.query(sql, values);
149
- return result[0];
150
- }
151
-
152
- // ----------------------------- get entity with relations
153
-
154
- // ----------------------------- create entity with relations
155
- async createEntityWithRelation(
156
- entityType: string,
157
- data: Record<string, any>,
158
- loggedInUser: any,
159
- ): Promise<any> {
160
- const organizationId = loggedInUser.organization_id;
161
-
162
- const repo = this.reflectionHelper.getRepoService('EntityRelation');
163
-
164
- const getRelation = await repo.find({
165
- where: {
166
- organization_id: organizationId,
167
- source_entity_type: entityType,
168
- },
169
- });
170
-
171
- // const getRelation = await this.dataSource.query(
172
- // `SELECT *
173
- // FROM frm_entity_relation
174
- // WHERE organization_id = $1
175
- // AND source_entity_type = $2`,
176
- // [organizationId, entityType],
177
- // );
178
-
179
- const { mappedEntities, ...mainData } = data;
180
-
181
- // create main entity
182
- const createdEntityData = await this.createEntity(
183
- entityType,
184
- mainData,
185
- loggedInUser,
186
- );
187
- const mainID = createdEntityData.insertId || createdEntityData.id;
188
-
189
- if (mappedEntities && getRelation.length > 0) {
190
- for (const relation of getRelation) {
191
- const targetEntityType = relation.target_entity_type;
192
- const relationType = relation.relation_type;
193
- const relationId = relation.relation_id;
194
-
195
- if (!mappedEntities[targetEntityType]) continue;
196
-
197
- // normalize: always array
198
- const entityDataArray = Array.isArray(mappedEntities[targetEntityType])
199
- ? mappedEntities[targetEntityType]
200
- : [mappedEntities[targetEntityType]];
201
-
202
- for (const item of entityDataArray) {
203
- const itemWithRef = {
204
- ...item,
205
- entity_type: targetEntityType,
206
- };
207
-
208
- const createdRelatedEntity = await this.createEntity(
209
- targetEntityType,
210
- itemWithRef,
211
- loggedInUser,
212
- mainID, // this will pass for parent_id
213
- );
214
-
215
- const relationRepo =
216
- this.reflectionHelper.getRepoService('EntityRelationData');
217
-
218
- await relationRepo.save({
219
- organizationId: organizationId,
220
- source_entity_id: mainID,
221
- source_entity_type: entityType,
222
- target_entity_id: createdRelatedEntity.id,
223
- targetEntityType: targetEntityType,
224
- relation_type: relationType,
225
- });
226
-
227
- // await this.dataSource.query(
228
- // `INSERT INTO frm_entity_relation_data (organization_id, source_entity_id, source_entity_type,
229
- // target_entity_id, target_entity_type, relation_type)
230
- // VALUES ($1, $2, $3, $4, $5, $6)`,
231
- // [
232
- // organizationId,
233
- // mainID,
234
- // entityType,
235
- // createdRelatedEntity.id,
236
- // targetEntityType,
237
- // relationType,
238
- // ],
239
- // );
240
- }
241
- }
242
- }
243
-
244
- return {
245
- mainEntity: {
246
- id: mainID,
247
- entityType,
248
- data: createdEntityData,
249
- },
250
- };
251
- }
252
-
253
- // ----------------------------- get entity with relations
254
- async getEntityWithRelation(
255
- entityType: string,
256
- id: number | string,
257
- loggedInUser: any,
258
- ): Promise<any> {
259
- const mainEntity = await this.getEntityByDataSource(
260
- entityType,
261
- id,
262
- loggedInUser,
263
- );
264
- const relationRepo = this.reflectionHelper.getRepoService('EntityRelation');
265
- const relatedEntityRepo =
266
- this.reflectionHelper.getRepoService('EntityRelationData');
267
-
268
- const relations = await relationRepo.find({
269
- where: { source_entity_type: entityType },
270
- });
271
-
272
- const targetTypes = relations.map((r) => r.target_entity_type);
273
-
274
- if (targetTypes.length === 0) {
275
- return {
276
- entity_type: entityType,
277
- ...mainEntity,
278
- };
279
- }
280
-
281
- const relatedEntities = await relatedEntityRepo.find({
282
- where: {
283
- source_entity_id: id,
284
- target_entity_type: In(targetTypes),
285
- },
286
- });
287
-
288
- // Format response to match create entity structure
289
- const response: any = {
290
- entity_type: entityType,
291
- ...mainEntity,
292
- };
293
-
294
- if (relatedEntities.length > 0) {
295
- response.mappedEntities = await this.formatMappedEntities(
296
- relatedEntities,
297
- loggedInUser,
298
- );
299
- }
300
-
301
- return response;
302
- }
303
-
304
- // ----------------------------- formatMappedEntities
305
- async formatMappedEntities(
306
- relatedEntities: any[],
307
- loggedInUser: any,
308
- ): Promise<any> {
309
- const mappedEntities: any = {};
310
-
311
- for (const relation of relatedEntities) {
312
- const targetEntityType = relation.target_entity_type;
313
- const targetEntityId = relation.target_entity_id;
314
-
315
- const entityData = await this.getEntity(
316
- targetEntityType,
317
- targetEntityId,
318
- loggedInUser,
319
- );
320
-
321
- if (!mappedEntities[targetEntityType]) {
322
- mappedEntities[targetEntityType] = [];
323
- }
324
-
325
- mappedEntities[targetEntityType].push(entityData);
326
- }
327
-
328
- return mappedEntities;
329
- }
330
-
331
- // ----------------------------- update with relations
332
-
333
- // ----------------------------- update entity with relations
334
- async updateEntityWithRelations(
335
- entityType: string,
336
- id: number | string,
337
- data: Record<string, any>,
338
- loggedInUser: any,
339
- ): Promise<any> {
340
- const organizationId = loggedInUser.organization_id;
341
- const { mappedEntities, ...mainData } = data;
342
-
343
- // Update main entity
344
- const updatedMainEntity = await this.updateEntity(
345
- entityType,
346
- id,
347
- mainData,
348
- loggedInUser,
349
- );
350
-
351
- const updatedRelations: Record<string, any> = {};
352
-
353
- if (mappedEntities) {
354
- const entityRelationRepo =
355
- this.reflectionHelper.getRepoService('EntityRelation');
356
- const getRelationDefs = await entityRelationRepo.find({
357
- where: {
358
- organization_id: organizationId,
359
- source_entity_type: entityType,
360
- },
361
- });
362
-
363
- for (const [targetEntityType, rawEntityData] of Object.entries(
364
- mappedEntities,
365
- )) {
366
- const relationDef = getRelationDefs.find(
367
- (r) => r.target_entity_type === targetEntityType,
368
- );
369
- if (!relationDef) continue;
370
-
371
- const relationType = relationDef.relation_type;
372
- const entityArray = Array.isArray(rawEntityData)
373
- ? rawEntityData
374
- : [rawEntityData];
375
-
376
- // Delete previous relations and related entities
377
- // Create/update new entities & relations
378
- const updatedEntities: any[] = [];
379
-
380
- for (const item of entityArray) {
381
- let targetEntityId;
382
- let entityData;
383
-
384
- if (item.id) {
385
- // Update existing entity
386
- await this.updateEntity(
387
- targetEntityType,
388
- item.id,
389
- item,
390
- loggedInUser,
391
- Number(id), // pass main entity id as parent_id
392
- );
393
- targetEntityId = item.id;
394
- entityData = await this.getEntity(
395
- targetEntityType,
396
- targetEntityId,
397
- loggedInUser,
398
- );
399
- } else {
400
- // Delete the related entity if we are creating a new one
401
- // for (const existingRel of existingRelationsForType) {
402
- // await this.deleteEntity(
403
- // existingRel.target_entity_type,
404
- // existingRel.target_entity_id,
405
- // loggedInUser,
406
- // );
407
-
408
- // // Delete the relation row
409
- // await this.dataSource.query(
410
- // `DELETE FROM frm_entity_relation_data WHERE id = ?`,
411
- // [existingRel.id],
412
- // );
413
- // }
414
- // Create new entity
415
- const createdEntity = await this.createEntity(
416
- targetEntityType,
417
- item,
418
- loggedInUser,
419
- Number(id), // pass main entity id as parent_id
420
- );
421
- targetEntityId = createdEntity.insertId || createdEntity.id;
422
- entityData = await this.getEntity(
423
- targetEntityType,
424
- targetEntityId,
425
- loggedInUser,
426
- );
427
-
428
- // Insert relation as per new entity created
429
- const entityRelationDataRepo =
430
- this.reflectionHelper.getRepoService('EntityRelationData');
431
- await entityRelationDataRepo.save({
432
- organizationId: organizationId,
433
- source_entity_id: id,
434
- source_entity_type: entityType,
435
- target_entity_id: targetEntityId,
436
- targetEntityType: targetEntityType,
437
- relation_type: relationType,
438
- });
439
- }
440
-
441
- if (relationType === 'ONE_TO_MANY') {
442
- updatedEntities.push(entityData);
443
- } else if (
444
- relationType === 'ONE_TO_ONE' ||
445
- relationType === 'MANY_TO_ONE'
446
- ) {
447
- updatedEntities[0] = entityData; // single object
448
- }
449
- }
450
-
451
- // Assign to response mappedEntities
452
- updatedRelations[targetEntityType] =
453
- relationType === 'ONE_TO_MANY' ? updatedEntities : updatedEntities[0];
454
- }
455
- }
456
-
457
- return {
458
- mainEntity: {
459
- id,
460
- entityType,
461
- data: updatedMainEntity,
462
- },
463
- relatedEntities: updatedRelations,
464
- };
465
- }
466
-
467
- // -----------------------------
468
- async updateEntity(
469
- entityType: string,
470
- id: number | string,
471
- entityData: Record<string, any>,
472
- loggedInUser: any,
473
- mainID?: number,
474
- ): Promise<any> {
475
- const organizationId = loggedInUser.organization_id;
476
-
477
- const tableName = await this.getTableName(entityType, organizationId);
478
- const validAttributes = await this.getAttributeCodes(
479
- entityType,
480
- organizationId,
481
- );
482
-
483
- const updates: string[] = [];
484
- const values: any[] = [];
485
- let idx = 1;
486
-
487
- // Auto fields
488
- entityData.modified_date = new Date();
489
- if (loggedInUser) {
490
- entityData.modified_by = loggedInUser.id;
491
-
492
- if (!entityData.organization_id && entityData.entity_type !== 'ORG')
493
- entityData.organization_id = loggedInUser.organization_id;
494
-
495
- if (!entityData.enterprise_id)
496
- entityData.enterprise_id = loggedInUser.enterprise_id;
497
- }
498
-
499
- if (mainID) {
500
- entityData.parent_id = mainID;
501
- }
502
-
503
- // Add bypass columns if needed
504
- const bypassColumns = [
505
- 'created_date',
506
- 'created_by',
507
- 'modified_date',
508
- 'modified_by',
509
- 'organization_id',
510
- 'enterprise_id',
511
- 'level_type',
512
- 'level_id',
513
- 'status',
514
- 'entity_type',
515
- 'code',
516
- 'parent_id',
517
- ];
518
-
519
- for (const col of bypassColumns) {
520
- if (!validAttributes.some((attr) => attr.attribute_key === col)) {
521
- validAttributes.push({
522
- attribute_key: col,
523
- db_datatype: 'text',
524
- element_type: 'text',
525
- is_hidden: false,
526
- });
527
- }
528
- }
529
-
530
- // Build SET clause
531
- for (const key of Object.keys(entityData)) {
532
- if (validAttributes.some((attr) => attr.attribute_key === key)) {
533
- updates.push(`${key} = $${idx++}`);
534
- values.push(entityData[key]);
535
- }
536
- }
537
-
538
- if (updates.length === 0) {
539
- throw new Error('No valid attributes to update.');
540
- }
541
-
542
- // WHERE clause placeholder
543
- const idPlaceholder = `$${idx}`;
544
- values.push(id);
545
-
546
- const updateQuery = `
547
- UPDATE ${tableName}
548
- SET ${updates.join(', ')}
549
- WHERE id = ${idPlaceholder}
550
- `;
551
-
552
- return await this.entityManager.query(updateQuery, values);
553
- }
554
-
555
- async getEntityByDataSource(
556
- entityType: string,
557
- id: number | string,
558
- loggedInUser: any,
559
- ): Promise<any> {
560
- const organizationId = loggedInUser.organization_id;
561
-
562
- const dataSource = await this.getEntitySourceTableName(
563
- entityType,
564
- organizationId,
565
- );
566
- const validAttributes = await this.getAttributeCodes(
567
- entityType,
568
- organizationId,
569
- false,
570
- );
571
-
572
- const columns = validAttributes
573
- .map((attr) => `${attr.attribute_key}`)
574
- .join(', ');
575
- const selectQuery = `SELECT ${columns}
576
- FROM ${dataSource}
577
- WHERE id = $1`;
578
-
579
- const result = await this.entityManager.query(selectQuery, [id]);
580
- if (!result.length) return null;
581
-
582
- const row = result[0];
583
-
584
- // Convert boolean columns (1/0) into true/false
585
- for (const attr of validAttributes) {
586
- if (
587
- attr.db_datatype == 'boolean' &&
588
- row[attr.attribute_key] !== undefined
589
- ) {
590
- row[attr.attribute_key] = row[attr.attribute_key] == 1 ? true : false;
591
- } else if (
592
- attr.element_type == 'upload' &&
593
- row[attr.attribute_key] !== undefined
594
- ) {
595
- row[attr.attribute_key] =
596
- row[attr.attribute_key] != null
597
- ? await this.mediaDataService.getMediaDownloadUrl(
598
- Number(row[attr.attribute_key]),
599
- loggedInUser,
600
- )
601
- : null;
602
- }
603
- }
604
-
605
- return row;
606
- }
607
-
608
- // -----------------------------
609
- //TODO : make it normal getEntity function make another function if for resolve data
610
- async getEntity(
611
- entityType: string,
612
- id: number | string,
613
- loggedInUser: any,
614
- ): Promise<any> {
615
- const organizationId = loggedInUser.organization_id;
616
-
617
- const tableName = await this.getTableName(entityType, organizationId);
618
- const dataSource = await this.getEntitySourceTableName(
619
- entityType,
620
- organizationId,
621
- );
622
- const validAttributes = await this.getAttributeCodes(
623
- entityType,
624
- organizationId,
625
- );
626
-
627
- const columns = validAttributes
628
- .map((attr) => `t.${attr.attribute_key}`)
629
- .join(', ');
630
- const selectQuery = `SELECT ${columns}
631
- FROM ${tableName} t
632
- WHERE id = $1`;
633
-
634
- const result = await this.entityManager.query(selectQuery, [id]);
635
- if (!result.length) return null;
636
-
637
- const row = result[0];
638
-
639
- // Convert boolean columns (1/0) into true/false
640
- for (const attr of validAttributes) {
641
- if (
642
- attr.db_datatype == 'boolean' &&
643
- row[attr.attribute_key] !== undefined
644
- ) {
645
- row[attr.attribute_key] = row[attr.attribute_key] == 1 ? true : false;
646
- } else if (
647
- attr.element_type == 'upload' &&
648
- row[attr.attribute_key] !== undefined
649
- ) {
650
- row[attr.attribute_key] =
651
- row[attr.attribute_key] != null
652
- ? await this.mediaDataService.getMediaDownloadUrl(
653
- Number(row[attr.attribute_key]),
654
- loggedInUser,
655
- )
656
- : null;
657
- }
658
- }
659
-
660
- return row;
661
- }
662
-
663
- private async getEntitySourceTableName(
664
- entityType: string,
665
- organizationId: string,
666
- ): Promise<string> {
667
- const result = await this.entityMasterRepo.getEntityByMappedEntityType(
668
- entityType,
669
- organizationId,
670
- );
671
-
672
- if (!result) {
673
- console.log(`Entity type '${entityType}' not found in frm_entity_master`);
674
- throw new BadRequestException();
675
- }
676
-
677
- return result.data_source;
678
- }
679
-
680
- // -----------------------------
681
- private async getTableName(
682
- entityType: string,
683
- organizationId: string,
684
- ): Promise<string> {
685
- let entityMaster = await this.entityMasterRepo.getEntityByMappedEntityType(
686
- entityType,
687
- organizationId,
688
- );
689
-
690
- if (!entityMaster) {
691
- console.log(`Entity type '${entityType}' not found in frm_entity_master`);
692
- throw new BadRequestException();
693
- }
694
-
695
- return entityMaster.db_table_name;
696
- }
697
-
698
- private async getAttributeCodes(
699
- entityType: string,
700
- organizationId: string,
701
- isHidden = true,
702
- ) {
703
- const attributeMasterRepo =
704
- this.reflectionHelper.getRepoService('AttributeMaster');
705
-
706
- const qb = attributeMasterRepo
707
- .createQueryBuilder('fea')
708
- .select('fea.attribute_key', 'attribute_key')
709
- .addSelect('MAX(fea.db_datatype)', 'db_datatype')
710
- .addSelect('MAX(fea.element_type)', 'element_type')
711
- .addSelect('bool_or(fea.is_hidden)', 'is_hidden')
712
- .where('fea.mapped_entity_type = :entityType', { entityType })
713
- .andWhere('fea.organization_id = :organizationId', { organizationId });
714
-
715
- if (isHidden) {
716
- qb.andWhere('(fea.is_hidden IS NULL OR fea.is_hidden = false)');
717
- }
718
-
719
- qb.groupBy('fea.attribute_key');
720
-
721
- const result = await qb.getRawMany();
722
-
723
- return result.map((row: any) => ({
724
- attribute_key: row.attribute_key,
725
- db_datatype: row.db_datatype,
726
- element_type: row.element_type,
727
- is_hidden: row.is_hidden != null ? row.is_hidden === true : undefined,
728
- }));
729
- }
730
-
731
- private async deleteEntity(
732
- entityType: string,
733
- id: number | string,
734
- loggedInUser: any,
735
- ): Promise<any> {
736
- const organizationId = loggedInUser.organization_id;
737
-
738
- const tableName = await this.getTableName(entityType, organizationId);
739
-
740
- const deleteQuery = `DELETE
741
- FROM \`${tableName}\`
742
- WHERE id = $1`;
743
- const result = await this.entityManager.query(deleteQuery, [id]);
744
- return result;
745
- }
746
-
747
- // -----------------------------
748
-
749
- async getEntitiesDropdownList(
750
- loggedInUser: any,
751
- appcode?: string,
752
- ): Promise<any> {
753
- const organizationId = loggedInUser.organization_id;
754
-
755
- let query = `SELECT name as label, mapped_entity_type as value
756
- FROM frm_entity_master
757
- WHERE organization_id = $1`;
758
- const params = [organizationId];
759
-
760
- if (appcode) {
761
- query += ` AND appcode = $2`;
762
- params.push(appcode);
763
- }
764
-
765
- const dropdown = await this.entityManager.query(query, params);
766
- return dropdown;
767
- }
768
-
769
- async getCode(entityType: string, loggedInUser: any): Promise<string> {
770
- const organizationId = loggedInUser.organization_id;
771
-
772
- // 1. Get db_table_name from entity master
773
-
774
- const result = await this.entityMasterRepo.getEntityByMappedEntityType(
775
- entityType,
776
- organizationId,
777
- );
778
-
779
- if (!result) {
780
- throw new Error(
781
- `Entity type '${entityType}' not found in frm_entity_master for org '${organizationId}'`,
782
- );
783
- }
784
-
785
- const tableName = result.db_table_name;
786
-
787
- // 2. Get current max sequence number from that table
788
- const seqResult = await this.entityManager.query(
789
- `SELECT MAX(id) AS max_seq_no
790
- FROM ${tableName}
791
- WHERE entity_type = $1`,
792
- [entityType],
793
- );
794
-
795
- let maxSeqNo = seqResult?.[0]?.max_seq_no
796
- ? Number(seqResult[0].max_seq_no)
797
- : 0;
798
-
799
- maxSeqNo += 1;
800
-
801
- // 3. Return generated code
802
- return `${entityType}${maxSeqNo}`;
803
- }
804
-
805
- async getResolvedEntity(
806
- id: number,
807
- entity: string,
808
- loggedInUser: UserData,
809
- ): Promise<any> {
810
- const leadData = await this.getEntityWithRelation(entity, id, loggedInUser);
811
-
812
- const { mappedEntities, ...data } = leadData as any;
813
-
814
- const resolvedData = await this.resolverService.getResolvedData(
815
- loggedInUser,
816
- data,
817
- entity,
818
- );
819
-
820
- if (mappedEntities) {
821
- resolvedData.mappedEntities = {};
822
- for (const [entityType, entities] of Object.entries(mappedEntities)) {
823
- if (Array.isArray(entities)) {
824
- resolvedData.mappedEntities[entityType] = [];
825
- for (const item of entities) {
826
- const resolvedItem = await this.resolverService.getResolvedData(
827
- loggedInUser,
828
- item,
829
- entityType,
830
- );
831
- resolvedData.mappedEntities[entityType].push(resolvedItem);
832
- }
833
- } else {
834
- resolvedData.mappedEntities[entityType] =
835
- await this.resolverService.getResolvedData(
836
- loggedInUser,
837
- entities,
838
- entityType,
839
- );
840
- }
841
- }
842
- }
843
-
844
- return resolvedData;
845
- }
846
- }
1
+ import { BadRequestException, Injectable } from '@nestjs/common';
2
+ import { STATUS_ACTIVE } from 'src/constant/global.constant';
3
+ import { EntityManager, In } from 'typeorm';
4
+ import { UserData } from 'src/module/user/entity/user.entity';
5
+ import { MediaDataService } from './media-data.service';
6
+ import { ResolverService } from './resolver.service';
7
+ import { EntityMasterRepository } from '../repository/entity-master.repository';
8
+ import { ReflectionHelper } from '../../../utils/service/reflection-helper.service';
9
+
10
+ @Injectable()
11
+ export class EntityDynamicService {
12
+ constructor(
13
+ private readonly entityManager: EntityManager,
14
+ private readonly mediaDataService: MediaDataService,
15
+ private readonly resolverService: ResolverService,
16
+ private readonly entityMasterRepo: EntityMasterRepository,
17
+ private readonly reflectionHelper: ReflectionHelper,
18
+ ) {}
19
+
20
+ // -----------------------------
21
+ async createEntity(
22
+ entityType: string,
23
+ entityData: Record<string, any>,
24
+ loggedInUser: any,
25
+ mainID?: number,
26
+ ): Promise<any> {
27
+ const organizationId = loggedInUser.organization_id;
28
+
29
+ const tableName = await this.getTableName(entityType, organizationId);
30
+ const validAttributes = await this.getAttributeCodes(
31
+ entityType,
32
+ organizationId,
33
+ );
34
+
35
+ // -------------------------------------------------------
36
+ // AUTO fields
37
+ // -------------------------------------------------------
38
+ entityData.created_date = new Date();
39
+
40
+ if (loggedInUser) {
41
+ entityData.created_by = loggedInUser.id;
42
+
43
+ if (!entityData.organization_id)
44
+ entityData.organization_id = loggedInUser.organization_id;
45
+
46
+ if (!entityData.enterprise_id)
47
+ entityData.enterprise_id = loggedInUser.enterprise_id;
48
+
49
+ if (!entityData.level_type)
50
+ entityData.level_type = loggedInUser.level_type;
51
+
52
+ if (!entityData.level_id) entityData.level_id = loggedInUser.level_id;
53
+
54
+ if (!entityData.entity_type) entityData.entity_type = entityType;
55
+ }
56
+
57
+ // -------------------------------------------------------
58
+ // STATUS
59
+ // -------------------------------------------------------
60
+ const listMasterItemsRepo =
61
+ this.reflectionHelper.getRepoService('ListMasterItems');
62
+ const statusList = listMasterItemsRepo.find({
63
+ where: {
64
+ code: STATUS_ACTIVE,
65
+ organization_id: organizationId,
66
+ },
67
+ });
68
+
69
+ if (!entityData.status) entityData.status = statusList[0]?.id;
70
+
71
+ // -------------------------------------------------------
72
+ // AUTO-CODE GENERATION (POSTGRES SAFE)
73
+ // -------------------------------------------------------
74
+ if (!entityData.code && entityData.entity_type) {
75
+ // Extract integer suffix
76
+ const result = await this.entityManager.query(
77
+ `
78
+ SELECT MAX(id) AS max_seq_no
79
+ FROM ${tableName}
80
+ WHERE entity_type = $1
81
+ `,
82
+ [entityData.entity_type],
83
+ );
84
+
85
+ let maxSeq = Number(result?.[0]?.max_seq_no) || 0;
86
+ maxSeq++;
87
+ entityData.code = `${entityData.entity_type}${maxSeq}`;
88
+ }
89
+
90
+ // -------------------------------------------------------
91
+ // Parent ID
92
+ // -------------------------------------------------------
93
+ if (mainID) {
94
+ entityData.parent_id = mainID;
95
+ }
96
+
97
+ // -------------------------------------------------------
98
+ // BYPASS COLUMNS
99
+ // -------------------------------------------------------
100
+ const bypassColumns = [
101
+ 'created_date',
102
+ 'created_by',
103
+ 'organization_id',
104
+ 'enterprise_id',
105
+ 'level_type',
106
+ 'level_id',
107
+ 'status',
108
+ 'entity_type',
109
+ 'code',
110
+ 'parent_id',
111
+ ];
112
+
113
+ for (const col of bypassColumns) {
114
+ if (!validAttributes.some((a) => a.attribute_key === col)) {
115
+ validAttributes.push({
116
+ attribute_key: col,
117
+ is_hidden: false,
118
+ db_datatype: 'text',
119
+ element_type: 'text',
120
+ });
121
+ }
122
+ }
123
+
124
+ // -------------------------------------------------------
125
+ // BUILD INSERT QUERY (POSTGRES FORMAT)
126
+ // -------------------------------------------------------
127
+ const columns: string[] = [];
128
+ const values: any[] = [];
129
+ let idx = 1;
130
+ const placeholders: string[] = [];
131
+
132
+ for (const attr of validAttributes) {
133
+ if (attr.attribute_key === 'id') continue;
134
+
135
+ columns.push(attr.attribute_key);
136
+ values.push(entityData[attr.attribute_key] ?? null);
137
+ placeholders.push(`$${idx++}`);
138
+ }
139
+
140
+ const colList = columns.map((c) => `"${c}"`).join(', ');
141
+ const placeholderList = placeholders.join(', ');
142
+
143
+ const sql = `
144
+ INSERT INTO ${tableName} (${colList})
145
+ VALUES (${placeholderList}) RETURNING id
146
+ `;
147
+
148
+ const result = await this.entityManager.query(sql, values);
149
+ return result[0];
150
+ }
151
+
152
+ // ----------------------------- get entity with relations
153
+
154
+ // ----------------------------- create entity with relations
155
+ async createEntityWithRelation(
156
+ entityType: string,
157
+ data: Record<string, any>,
158
+ loggedInUser: any,
159
+ ): Promise<any> {
160
+ const organizationId = loggedInUser.organization_id;
161
+
162
+ const repo = this.reflectionHelper.getRepoService('EntityRelation');
163
+
164
+ const getRelation = await repo.find({
165
+ where: {
166
+ organization_id: organizationId,
167
+ source_entity_type: entityType,
168
+ },
169
+ });
170
+
171
+ const { mappedEntities, ...mainData } = data;
172
+
173
+ // create main entity
174
+ const createdEntityData = await this.createEntity(
175
+ entityType,
176
+ mainData,
177
+ loggedInUser,
178
+ );
179
+ const mainID = createdEntityData.insertId || createdEntityData.id;
180
+
181
+ if (mappedEntities && getRelation.length > 0) {
182
+ for (const relation of getRelation) {
183
+ const targetEntityType = relation.target_entity_type;
184
+ const relationType = relation.relation_type;
185
+ const relationId = relation.relation_id;
186
+
187
+ if (!mappedEntities[targetEntityType]) continue;
188
+
189
+ // normalize: always array
190
+ const entityDataArray = Array.isArray(mappedEntities[targetEntityType])
191
+ ? mappedEntities[targetEntityType]
192
+ : [mappedEntities[targetEntityType]];
193
+
194
+ for (const item of entityDataArray) {
195
+ const itemWithRef = {
196
+ ...item,
197
+ entity_type: targetEntityType,
198
+ };
199
+
200
+ const createdRelatedEntity = await this.createEntity(
201
+ targetEntityType,
202
+ itemWithRef,
203
+ loggedInUser,
204
+ mainID, // this will pass for parent_id
205
+ );
206
+
207
+ const relationRepo =
208
+ this.reflectionHelper.getRepoService('EntityRelationData');
209
+
210
+ await relationRepo.save({
211
+ organizationId: organizationId,
212
+ source_entity_id: mainID,
213
+ source_entity_type: entityType,
214
+ target_entity_id: createdRelatedEntity.id,
215
+ targetEntityType: targetEntityType,
216
+ relation_type: relationType,
217
+ });
218
+ }
219
+ }
220
+ }
221
+
222
+ return {
223
+ mainEntity: {
224
+ id: mainID,
225
+ entityType,
226
+ data: createdEntityData,
227
+ },
228
+ };
229
+ }
230
+
231
+ // ----------------------------- get entity with relations
232
+ async getEntityWithRelation(
233
+ entityType: string,
234
+ id: number | string,
235
+ loggedInUser: any,
236
+ ): Promise<any> {
237
+ const mainEntity = await this.getEntityByDataSource(
238
+ entityType,
239
+ id,
240
+ loggedInUser,
241
+ );
242
+ const relationRepo = this.reflectionHelper.getRepoService('EntityRelation');
243
+ const relatedEntityRepo =
244
+ this.reflectionHelper.getRepoService('EntityRelationData');
245
+
246
+ const relations = await relationRepo.find({
247
+ where: { source_entity_type: entityType },
248
+ });
249
+
250
+ const targetTypes = relations.map((r) => r.target_entity_type);
251
+
252
+ if (targetTypes.length === 0) {
253
+ return {
254
+ entity_type: entityType,
255
+ ...mainEntity,
256
+ };
257
+ }
258
+
259
+ const relatedEntities = await relatedEntityRepo.find({
260
+ where: {
261
+ source_entity_id: id,
262
+ target_entity_type: In(targetTypes),
263
+ },
264
+ });
265
+
266
+ // Format response to match create entity structure
267
+ const response: any = {
268
+ entity_type: entityType,
269
+ ...mainEntity,
270
+ };
271
+
272
+ if (relatedEntities.length > 0) {
273
+ response.mappedEntities = await this.formatMappedEntities(
274
+ relatedEntities,
275
+ loggedInUser,
276
+ );
277
+ }
278
+
279
+ return response;
280
+ }
281
+
282
+ // ----------------------------- formatMappedEntities
283
+ async formatMappedEntities(
284
+ relatedEntities: any[],
285
+ loggedInUser: any,
286
+ ): Promise<any> {
287
+ const mappedEntities: any = {};
288
+
289
+ for (const relation of relatedEntities) {
290
+ const targetEntityType = relation.target_entity_type;
291
+ const targetEntityId = relation.target_entity_id;
292
+
293
+ const entityData = await this.getEntity(
294
+ targetEntityType,
295
+ targetEntityId,
296
+ loggedInUser,
297
+ );
298
+
299
+ if (!mappedEntities[targetEntityType]) {
300
+ mappedEntities[targetEntityType] = [];
301
+ }
302
+
303
+ mappedEntities[targetEntityType].push(entityData);
304
+ }
305
+
306
+ return mappedEntities;
307
+ }
308
+
309
+ // ----------------------------- update with relations
310
+
311
+ // ----------------------------- update entity with relations
312
+ async updateEntityWithRelations(
313
+ entityType: string,
314
+ id: number | string,
315
+ data: Record<string, any>,
316
+ loggedInUser: any,
317
+ ): Promise<any> {
318
+ const organizationId = loggedInUser.organization_id;
319
+ const { mappedEntities, ...mainData } = data;
320
+
321
+ // Update main entity
322
+ const updatedMainEntity = await this.updateEntity(
323
+ entityType,
324
+ id,
325
+ mainData,
326
+ loggedInUser,
327
+ );
328
+
329
+ const updatedRelations: Record<string, any> = {};
330
+
331
+ if (mappedEntities) {
332
+ const entityRelationRepo =
333
+ this.reflectionHelper.getRepoService('EntityRelation');
334
+ const getRelationDefs = await entityRelationRepo.find({
335
+ where: {
336
+ organization_id: organizationId,
337
+ source_entity_type: entityType,
338
+ },
339
+ });
340
+
341
+ for (const [targetEntityType, rawEntityData] of Object.entries(
342
+ mappedEntities,
343
+ )) {
344
+ const relationDef = getRelationDefs.find(
345
+ (r) => r.target_entity_type === targetEntityType,
346
+ );
347
+ if (!relationDef) continue;
348
+
349
+ const relationType = relationDef.relation_type;
350
+ const entityArray = Array.isArray(rawEntityData)
351
+ ? rawEntityData
352
+ : [rawEntityData];
353
+
354
+ // Delete previous relations and related entities
355
+ // Create/update new entities & relations
356
+ const updatedEntities: any[] = [];
357
+
358
+ for (const item of entityArray) {
359
+ let targetEntityId;
360
+ let entityData;
361
+
362
+ if (item.id) {
363
+ // Update existing entity
364
+ await this.updateEntity(
365
+ targetEntityType,
366
+ item.id,
367
+ item,
368
+ loggedInUser,
369
+ Number(id), // pass main entity id as parent_id
370
+ );
371
+ targetEntityId = item.id;
372
+ entityData = await this.getEntity(
373
+ targetEntityType,
374
+ targetEntityId,
375
+ loggedInUser,
376
+ );
377
+ } else {
378
+ // Create new entity
379
+ const createdEntity = await this.createEntity(
380
+ targetEntityType,
381
+ item,
382
+ loggedInUser,
383
+ Number(id), // pass main entity id as parent_id
384
+ );
385
+ targetEntityId = createdEntity.insertId || createdEntity.id;
386
+ entityData = await this.getEntity(
387
+ targetEntityType,
388
+ targetEntityId,
389
+ loggedInUser,
390
+ );
391
+
392
+ // Insert relation as per new entity created
393
+ const entityRelationDataRepo =
394
+ this.reflectionHelper.getRepoService('EntityRelationData');
395
+ await entityRelationDataRepo.save({
396
+ organizationId: organizationId,
397
+ source_entity_id: id,
398
+ source_entity_type: entityType,
399
+ target_entity_id: targetEntityId,
400
+ targetEntityType: targetEntityType,
401
+ relation_type: relationType,
402
+ });
403
+ }
404
+
405
+ if (relationType === 'ONE_TO_MANY') {
406
+ updatedEntities.push(entityData);
407
+ } else if (
408
+ relationType === 'ONE_TO_ONE' ||
409
+ relationType === 'MANY_TO_ONE'
410
+ ) {
411
+ updatedEntities[0] = entityData; // single object
412
+ }
413
+ }
414
+
415
+ // Assign to response mappedEntities
416
+ updatedRelations[targetEntityType] =
417
+ relationType === 'ONE_TO_MANY' ? updatedEntities : updatedEntities[0];
418
+ }
419
+ }
420
+
421
+ return {
422
+ mainEntity: {
423
+ id,
424
+ entityType,
425
+ data: updatedMainEntity,
426
+ },
427
+ relatedEntities: updatedRelations,
428
+ };
429
+ }
430
+
431
+ // -----------------------------
432
+ async updateEntity(
433
+ entityType: string,
434
+ id: number | string,
435
+ entityData: Record<string, any>,
436
+ loggedInUser: any,
437
+ mainID?: number,
438
+ ): Promise<any> {
439
+ const organizationId = loggedInUser.organization_id;
440
+
441
+ const tableName = await this.getTableName(entityType, organizationId);
442
+ const validAttributes = await this.getAttributeCodes(
443
+ entityType,
444
+ organizationId,
445
+ );
446
+
447
+ const updates: string[] = [];
448
+ const values: any[] = [];
449
+ let idx = 1;
450
+
451
+ // Auto fields
452
+ entityData.modified_date = new Date();
453
+ if (loggedInUser) {
454
+ entityData.modified_by = loggedInUser.id;
455
+
456
+ if (!entityData.organization_id && entityData.entity_type !== 'ORG')
457
+ entityData.organization_id = loggedInUser.organization_id;
458
+
459
+ if (!entityData.enterprise_id)
460
+ entityData.enterprise_id = loggedInUser.enterprise_id;
461
+ }
462
+
463
+ if (mainID) {
464
+ entityData.parent_id = mainID;
465
+ }
466
+
467
+ // Add bypass columns if needed
468
+ const bypassColumns = [
469
+ 'created_date',
470
+ 'created_by',
471
+ 'modified_date',
472
+ 'modified_by',
473
+ 'organization_id',
474
+ 'enterprise_id',
475
+ 'level_type',
476
+ 'level_id',
477
+ 'status',
478
+ 'entity_type',
479
+ 'code',
480
+ 'parent_id',
481
+ ];
482
+
483
+ for (const col of bypassColumns) {
484
+ if (!validAttributes.some((attr) => attr.attribute_key === col)) {
485
+ validAttributes.push({
486
+ attribute_key: col,
487
+ db_datatype: 'text',
488
+ element_type: 'text',
489
+ is_hidden: false,
490
+ });
491
+ }
492
+ }
493
+
494
+ // Build SET clause
495
+ for (const key of Object.keys(entityData)) {
496
+ if (validAttributes.some((attr) => attr.attribute_key === key)) {
497
+ updates.push(`${key} = $${idx++}`);
498
+ values.push(entityData[key]);
499
+ }
500
+ }
501
+
502
+ if (updates.length === 0) {
503
+ throw new Error('No valid attributes to update.');
504
+ }
505
+
506
+ // WHERE clause placeholder
507
+ const idPlaceholder = `$${idx}`;
508
+ values.push(id);
509
+
510
+ const updateQuery = `
511
+ UPDATE ${tableName}
512
+ SET ${updates.join(', ')}
513
+ WHERE id = ${idPlaceholder}
514
+ `;
515
+
516
+ return await this.entityManager.query(updateQuery, values);
517
+ }
518
+
519
+ async getEntityByDataSource(
520
+ entityType: string,
521
+ id: number | string,
522
+ loggedInUser: any,
523
+ ): Promise<any> {
524
+ const organizationId = loggedInUser.organization_id;
525
+
526
+ const dataSource = await this.getEntitySourceTableName(
527
+ entityType,
528
+ organizationId,
529
+ );
530
+ const validAttributes = await this.getAttributeCodes(
531
+ entityType,
532
+ organizationId,
533
+ false,
534
+ );
535
+
536
+ const columns = validAttributes
537
+ .map((attr) => `${attr.attribute_key}`)
538
+ .join(', ');
539
+ const selectQuery = `SELECT ${columns}
540
+ FROM ${dataSource}
541
+ WHERE id = $1`;
542
+
543
+ const result = await this.entityManager.query(selectQuery, [id]);
544
+ if (!result.length) return null;
545
+
546
+ const row = result[0];
547
+
548
+ // Convert boolean columns (1/0) into true/false
549
+ for (const attr of validAttributes) {
550
+ if (
551
+ attr.db_datatype == 'boolean' &&
552
+ row[attr.attribute_key] !== undefined
553
+ ) {
554
+ row[attr.attribute_key] = row[attr.attribute_key] == 1 ? true : false;
555
+ } else if (
556
+ attr.element_type == 'upload' &&
557
+ row[attr.attribute_key] !== undefined
558
+ ) {
559
+ row[attr.attribute_key] =
560
+ row[attr.attribute_key] != null
561
+ ? await this.mediaDataService.getMediaDownloadUrl(
562
+ Number(row[attr.attribute_key]),
563
+ loggedInUser,
564
+ )
565
+ : null;
566
+ }
567
+ }
568
+
569
+ return row;
570
+ }
571
+
572
+ // -----------------------------
573
+ //TODO : make it normal getEntity function make another function if for resolve data
574
+ async getEntity(
575
+ entityType: string,
576
+ id: number | string,
577
+ loggedInUser: any,
578
+ ): Promise<any> {
579
+ const organizationId = loggedInUser.organization_id;
580
+
581
+ const tableName = await this.getTableName(entityType, organizationId);
582
+ const dataSource = await this.getEntitySourceTableName(
583
+ entityType,
584
+ organizationId,
585
+ );
586
+ const validAttributes = await this.getAttributeCodes(
587
+ entityType,
588
+ organizationId,
589
+ );
590
+
591
+ const columns = validAttributes
592
+ .map((attr) => `t.${attr.attribute_key}`)
593
+ .join(', ');
594
+ const selectQuery = `SELECT ${columns}
595
+ FROM ${tableName} t
596
+ WHERE id = $1`;
597
+
598
+ const result = await this.entityManager.query(selectQuery, [id]);
599
+ if (!result.length) return null;
600
+
601
+ const row = result[0];
602
+
603
+ // Convert boolean columns (1/0) into true/false
604
+ for (const attr of validAttributes) {
605
+ if (
606
+ attr.db_datatype == 'boolean' &&
607
+ row[attr.attribute_key] !== undefined
608
+ ) {
609
+ row[attr.attribute_key] = row[attr.attribute_key] == 1 ? true : false;
610
+ } else if (
611
+ attr.element_type == 'upload' &&
612
+ row[attr.attribute_key] !== undefined
613
+ ) {
614
+ row[attr.attribute_key] =
615
+ row[attr.attribute_key] != null
616
+ ? await this.mediaDataService.getMediaDownloadUrl(
617
+ Number(row[attr.attribute_key]),
618
+ loggedInUser,
619
+ )
620
+ : null;
621
+ }
622
+ }
623
+
624
+ return row;
625
+ }
626
+
627
+ private async getEntitySourceTableName(
628
+ entityType: string,
629
+ organizationId: string,
630
+ ): Promise<string> {
631
+ const result = await this.entityMasterRepo.getEntityByMappedEntityType(
632
+ entityType,
633
+ organizationId,
634
+ );
635
+
636
+ if (!result) {
637
+ console.log(`Entity type '${entityType}' not found in frm_entity_master`);
638
+ throw new BadRequestException();
639
+ }
640
+
641
+ return result.data_source;
642
+ }
643
+
644
+ // -----------------------------
645
+ private async getTableName(
646
+ entityType: string,
647
+ organizationId: string,
648
+ ): Promise<string> {
649
+ let entityMaster = await this.entityMasterRepo.getEntityByMappedEntityType(
650
+ entityType,
651
+ organizationId,
652
+ );
653
+
654
+ if (!entityMaster) {
655
+ console.log(`Entity type '${entityType}' not found in frm_entity_master`);
656
+ throw new BadRequestException();
657
+ }
658
+
659
+ return entityMaster.db_table_name;
660
+ }
661
+
662
+ private async getAttributeCodes(
663
+ entityType: string,
664
+ organizationId: string,
665
+ isHidden = true,
666
+ ) {
667
+ const attributeMasterRepo =
668
+ this.reflectionHelper.getRepoService('AttributeMaster');
669
+
670
+ const qb = attributeMasterRepo
671
+ .createQueryBuilder('fea')
672
+ .select('fea.attribute_key', 'attribute_key')
673
+ .addSelect('MAX(fea.db_datatype)', 'db_datatype')
674
+ .addSelect('MAX(fea.element_type)', 'element_type')
675
+ .addSelect('bool_or(fea.is_hidden)', 'is_hidden')
676
+ .where('fea.mapped_entity_type = :entityType', { entityType })
677
+ .andWhere('fea.organization_id = :organizationId', { organizationId });
678
+
679
+ if (isHidden) {
680
+ qb.andWhere('(fea.is_hidden IS NULL OR fea.is_hidden = false)');
681
+ }
682
+
683
+ qb.groupBy('fea.attribute_key');
684
+
685
+ const result = await qb.getRawMany();
686
+
687
+ return result.map((row: any) => ({
688
+ attribute_key: row.attribute_key,
689
+ db_datatype: row.db_datatype,
690
+ element_type: row.element_type,
691
+ is_hidden: row.is_hidden != null ? row.is_hidden === true : undefined,
692
+ }));
693
+ }
694
+
695
+ private async deleteEntity(
696
+ entityType: string,
697
+ id: number | string,
698
+ loggedInUser: any,
699
+ ): Promise<any> {
700
+ const organizationId = loggedInUser.organization_id;
701
+
702
+ const tableName = await this.getTableName(entityType, organizationId);
703
+
704
+ const deleteQuery = `DELETE
705
+ FROM \`${tableName}\`
706
+ WHERE id = $1`;
707
+ const result = await this.entityManager.query(deleteQuery, [id]);
708
+ return result;
709
+ }
710
+
711
+ // -----------------------------
712
+
713
+ async getEntitiesDropdownList(
714
+ loggedInUser: any,
715
+ appcode?: string,
716
+ ): Promise<any> {
717
+ const organizationId = loggedInUser.organization_id;
718
+
719
+ let query = `SELECT name as label, mapped_entity_type as value
720
+ FROM frm_entity_master
721
+ WHERE organization_id = $1`;
722
+ const params = [organizationId];
723
+
724
+ if (appcode) {
725
+ query += ` AND appcode = $2`;
726
+ params.push(appcode);
727
+ }
728
+
729
+ const dropdown = await this.entityManager.query(query, params);
730
+ return dropdown;
731
+ }
732
+
733
+ async getCode(entityType: string, loggedInUser: any): Promise<string> {
734
+ const organizationId = loggedInUser.organization_id;
735
+
736
+ // 1. Get db_table_name from entity master
737
+
738
+ const result = await this.entityMasterRepo.getEntityByMappedEntityType(
739
+ entityType,
740
+ organizationId,
741
+ );
742
+
743
+ if (!result) {
744
+ throw new Error(
745
+ `Entity type '${entityType}' not found in frm_entity_master for org '${organizationId}'`,
746
+ );
747
+ }
748
+
749
+ const tableName = result.db_table_name;
750
+
751
+ // 2. Get current max sequence number from that table
752
+ const seqResult = await this.entityManager.query(
753
+ `SELECT MAX(id) AS max_seq_no
754
+ FROM ${tableName}
755
+ WHERE entity_type = $1`,
756
+ [entityType],
757
+ );
758
+
759
+ let maxSeqNo = seqResult?.[0]?.max_seq_no
760
+ ? Number(seqResult[0].max_seq_no)
761
+ : 0;
762
+
763
+ maxSeqNo += 1;
764
+
765
+ // 3. Return generated code
766
+ return `${entityType}${maxSeqNo}`;
767
+ }
768
+
769
+ async getResolvedEntity(
770
+ id: number,
771
+ entity: string,
772
+ loggedInUser: UserData,
773
+ ): Promise<any> {
774
+ const leadData = await this.getEntityWithRelation(entity, id, loggedInUser);
775
+
776
+ const { mappedEntities, ...data } = leadData as any;
777
+
778
+ const resolvedData = await this.resolverService.getResolvedData(
779
+ loggedInUser,
780
+ data,
781
+ entity,
782
+ );
783
+
784
+ if (mappedEntities) {
785
+ resolvedData.mappedEntities = {};
786
+ for (const [entityType, entities] of Object.entries(mappedEntities)) {
787
+ if (Array.isArray(entities)) {
788
+ resolvedData.mappedEntities[entityType] = [];
789
+ for (const item of entities) {
790
+ const resolvedItem = await this.resolverService.getResolvedData(
791
+ loggedInUser,
792
+ item,
793
+ entityType,
794
+ );
795
+ resolvedData.mappedEntities[entityType].push(resolvedItem);
796
+ }
797
+ } else {
798
+ resolvedData.mappedEntities[entityType] =
799
+ await this.resolverService.getResolvedData(
800
+ loggedInUser,
801
+ entities,
802
+ entityType,
803
+ );
804
+ }
805
+ }
806
+ }
807
+
808
+ return resolvedData;
809
+ }
810
+ }