rez_core 6.1.4 → 6.1.6

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