rez_core 6.1.5 → 6.1.7

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